From 4d2b1d51e4fe138f6b751e3020cd044991ba1844 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 15 Jun 2026 23:19:27 +0200 Subject: [PATCH 01/94] Update rcore_desktop_glfw.c --- src/platforms/rcore_desktop_glfw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index d885acf43..55b92ac79 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -1078,7 +1078,7 @@ Image GetClipboardImage(void) XID window = glfwGetX11Window(platform.handle); // Lazy-load X11 atoms - if(clipboard == 0) + if (clipboard == 0) { clipboard = XInternAtom(display, "CLIPBOARD", False); targetType = XInternAtom(display, "image/png", False); From 3973766b84f931413399a8617a90c6b9ac9212ab Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 15 Jun 2026 23:19:31 +0200 Subject: [PATCH 02/94] Update rexm.c --- tools/rexm/rexm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index 75eb3dc99..58ae835f7 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -1886,9 +1886,11 @@ int main(int argc, char *argv[]) printf(" test : Build and Test example for Desktop and Web platforms\n"); printf(" validate : Validate examples collection, generates report\n"); printf(" update : Validate and update examples collection, generates report\n\n"); + printf("OPTIONS:\n\n"); printf(" -h, --help : Show tool version and command line usage help\n"); printf(" -v, --verbose : Verbose mode, show additional logs on processes\n"); + printf("\nEXAMPLES:\n\n"); printf(" > rexm add shapes_custom_stars\n"); printf(" Add and updates new example provided \n\n"); From efef4e31dda94a7dfbc16f350518a2c0e876dcb6 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 16 Jun 2026 13:01:50 +0200 Subject: [PATCH 03/94] REVIEWED: `LoadImageFromTexture()` for Wasm https://github.com/raysan5/rguistyler/issues/10 Let's see if it breaks on some other platform... --- src/rlgl.h | 8 ++++++++ src/rtextures.c | 17 ++++++++++------- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index e1c0089dc..1c2f0c95e 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -3777,9 +3777,17 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format) // Attach our texture to FBO glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, id, 0); +#if defined(FBO_READ_TEXTURE_AS_RGBA) // Reading data as RGBA because FBO texture is configured as RGBA, despite binding another texture format pixels = RL_CALLOC(rlGetPixelDataSize(width, height, RL_PIXELFORMAT_UNCOMPRESSED_R8G8B8A8), 1); glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); +#else + // Reading data as original texture format, in some platforms (RPI, Wasm) it works + pixels = (unsigned char *)RL_MALLOC(GetPixelDataSize(texture.width, texture.height, texture.format)); + unsigned int glInternalFormat = 0, glFormat = 0, glType = 0; + rlGetGlTextureFormats(texture.format, &glInternalFormat, &glFormat, &glType); + glReadPixels(0, 0, texture.width, texture.height, glFormat, glType, pixels); +#endif glBindFramebuffer(GL_FRAMEBUFFER, 0); diff --git a/src/rtextures.c b/src/rtextures.c index 5b85401ee..e982a9d55 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -562,15 +562,18 @@ Image LoadImageFromTexture(Texture2D texture) { image.width = texture.width; image.height = texture.height; - image.format = texture.format; - image.mipmaps = 1; - -#if defined(GRAPHICS_API_OPENGL_ES2) - // NOTE: Data retrieved on OpenGL ES 2.0 should be RGBA, - // coming from FBO color buffer attachment, but it seems - // original texture format is retrieved on RPI... +#if defined(FBO_READ_TEXTURE_AS_RGBA) + // WARNING: On OpenGL ES 2.0/WebGL 1.0, there is no glGetTexImage() so, + // texture data is retrieved by creating an RGBA fbo, binding the texture + // to the fbo color attachment, and reading it as RGBA data with glReadPixels() + // Returned data *should* be RGBA but it seems on some platforms (RPI, WASM) + // original texture format is retrieved, so adding a define for this patch image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; +#else + image.format = texture.format; #endif + image.mipmaps = 1; + TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Pixel data retrieved successfully", texture.id); } else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Failed to retrieve pixel data", texture.id); From fa8aca87896241a01789b50ab6153c0c931260fc Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 16 Jun 2026 13:06:16 +0200 Subject: [PATCH 04/94] Update rlgl.h --- src/rlgl.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index 1c2f0c95e..ed5e50fb1 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -3783,10 +3783,10 @@ void *rlReadTexturePixels(unsigned int id, int width, int height, int format) glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); #else // Reading data as original texture format, in some platforms (RPI, Wasm) it works - pixels = (unsigned char *)RL_MALLOC(GetPixelDataSize(texture.width, texture.height, texture.format)); + pixels = (unsigned char *)RL_MALLOC(GetPixelDataSize(width, height, format)); unsigned int glInternalFormat = 0, glFormat = 0, glType = 0; - rlGetGlTextureFormats(texture.format, &glInternalFormat, &glFormat, &glType); - glReadPixels(0, 0, texture.width, texture.height, glFormat, glType, pixels); + rlGetGlTextureFormats(format, &glInternalFormat, &glFormat, &glType); + glReadPixels(0, 0, width, height, glFormat, glType, pixels); #endif glBindFramebuffer(GL_FRAMEBUFFER, 0); From f9c41a0866f5c9e0b72a50328c5c07d0c1848dc2 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 16 Jun 2026 21:12:12 +0200 Subject: [PATCH 05/94] Reemove trailing spaces --- src/external/rlsw.h | 6 +++--- src/platforms/rcore_desktop_rgfw.c | 10 +++++----- src/platforms/rcore_desktop_sdl.c | 2 +- src/platforms/rcore_memory.c | 2 +- src/rcore.c | 4 ++-- src/rtext.c | 2 +- src/rtextures.c | 4 ++-- tools/rexm/rexm.c | 6 +++--- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/external/rlsw.h b/src/external/rlsw.h index b98a3f684..bb6e11679 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -1240,8 +1240,8 @@ static inline float sw_fract(float x) // Xtensa architecture optimization // Fast reciprocal: 1-ULP accurate in ~7 instructions using the -// hardware `recip0.s` seed + two Newton-Raphson refinement steps -// All work stays in FPU registers — no `__divsf3` software call +// hardware `recip0.s` seed + two Newton-Raphson refinement steps +// All work stays in FPU registers — no `__divsf3` software call // Hot-path divisions in the rasterizer (span/triangle setup, perspective divide, etc.) call this // On non-Xtensa targets it transparently expands to `1.0f / x`, so generated code is identical to before #if defined(__XTENSA__) @@ -5388,7 +5388,7 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t if (xLoopStart >= xLoopEnd) return; // Nothing to draw // Get the current row and skip if outside the framebuffer - // Maybe this check is better suited elsewhere? + // Maybe this check is better suited elsewhere? int y = (int)start->position[1]; if (y < 0 || y >= RLSW.colorBuffer->height) return; diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index a2c005662..f6b269a1d 100644 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -471,7 +471,7 @@ static void RGFW_cb_mousenotifyfunc(const RGFW_event* e) // static void RGFW_cb_windowclosefunc(const RGFW_event* e) // { // if (e->common.win != platform.window) return; - + // // we don't want to close here. raylib handles it // // RGFW_window_setShouldClose(platform.window, true); // } @@ -493,7 +493,7 @@ static void RGFW_cb_dropfunc(const RGFW_event* e) CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], e->drop.value->data); - CORE.Window.dropFileCount++; + CORE.Window.dropFileCount++; } else TRACELOG(LOG_WARNING, "FILE: Maximum drag and drop files at once is limited to 1024 files!"); } @@ -594,7 +594,7 @@ static void RGFW_cb_windowmaximizefunc(const RGFW_event* e) static void RGFW_cb_windowminimizefunc(const RGFW_event* e) { if (e->common.win != platform.window) return; - + FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED); // The window was iconified } static void RGFW_cb_windowrestorefunc(const RGFW_event* e) @@ -616,7 +616,7 @@ static void RGFW_cb_windowmovefunc(const RGFW_event* e) static void RGFW_cb_keycharfunc(const RGFW_event* e) { if (e->common.win != platform.window) return; - + // NOTE: event.text.text data comes an UTF-8 text sequence but registering codepoints (int) // Check if there is space available in the queue if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE) @@ -1145,7 +1145,7 @@ void *GetWindowHandle(void) #elif defined(__linux__) #if defined(RGFW_X11) platform.windowHandleX11 = platform.window->src.window; // Type: Window (unsigned long) - handle = &platform.window->src.window; + handle = &platform.window->src.window; #elif defined(RGFW_WAYLAND) handle = (void *)platform.window->src.surface; // Type: struct wl_surface* #endif diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index d568ec095..8ff17271f 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -56,7 +56,7 @@ #include "SDL3/SDL.h" #elif defined(USING_SDL2_PROJECT) #include "SDL2/SDL.h" - #include "SDL2/SDL_syswm.h" // Required to get window handlers + #include "SDL2/SDL_syswm.h" // Required to get window handlers #else #include "SDL.h" #endif diff --git a/src/platforms/rcore_memory.c b/src/platforms/rcore_memory.c index e7934bd96..14c56a591 100644 --- a/src/platforms/rcore_memory.c +++ b/src/platforms/rcore_memory.c @@ -366,7 +366,7 @@ double GetTime(void) #if defined(_WIN32) LARGE_INTEGER currentTicks = { 0 }; QueryPerformanceCounter(¤tTicks); - + time = (double)(currentTicks.QuadPart - CORE.Time.base)/(double)platform.timerFrequency.QuadPart; #elif defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__) struct timespec ts = { 0 }; diff --git a/src/rcore.c b/src/rcore.c index a37400cf1..7455e3597 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -2263,11 +2263,11 @@ int FileMove(const char *srcPath, const char *dstPath) if (FileExists(srcPath)) { result = FileCopy(srcPath, dstPath); - + if (result == 0) { // Make sure file has been correctly copied before removing - if (FileExists(dstPath) && (GetFileLength(srcPath) == GetFileLength(dstPath))) + if (FileExists(dstPath) && (GetFileLength(srcPath) == GetFileLength(dstPath))) { result = FileRemove(srcPath); if (result != 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to remove source file after copy", srcPath); diff --git a/src/rtext.c b/src/rtext.c index a7f715ba3..75a73b813 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -580,7 +580,7 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int TRACELOG(LOG_INFO, "FONT: Data loaded successfully (%i pixel size | %i glyphs)", font.baseSize, font.glyphCount); } - else + else { TRACELOG(LOG_WARNING, "FONT: Font is not supported by LoadFontEx/LoadFontFromMemory or no glyphs found, reverted to default font"); font = GetFontDefault(); diff --git a/src/rtextures.c b/src/rtextures.c index e982a9d55..724fe73cd 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -573,7 +573,7 @@ Image LoadImageFromTexture(Texture2D texture) image.format = texture.format; #endif image.mipmaps = 1; - + TRACELOG(LOG_INFO, "TEXTURE: [ID %i] Pixel data retrieved successfully", texture.id); } else TRACELOG(LOG_WARNING, "TEXTURE: [ID %i] Failed to retrieve pixel data", texture.id); @@ -1503,7 +1503,7 @@ Image ImageTextEx(Font font, const char *text, float fontSize, float spacing, Co if ((codepoint != ' ') && (codepoint != '\t')) { Rectangle rec = { (float)(textOffsetX + font.glyphs[index].offsetX), (float)(textOffsetY + font.glyphs[index].offsetY), (float)font.recs[index].width, (float)font.recs[index].height }; - ImageDrawImagePro(&imText, font.glyphs[index].image, (Rectangle){ 0, 0, (float)font.glyphs[index].image.width, (float)font.glyphs[index].image.height }, + ImageDrawImagePro(&imText, font.glyphs[index].image, (Rectangle){ 0, 0, (float)font.glyphs[index].image.width, (float)font.glyphs[index].image.height }, rec, (Vector2){ 0 }, 0.0f, tint); } diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index 58ae835f7..f268a7d44 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -680,7 +680,7 @@ int main(int argc, char *argv[]) LOG("INFO: [%s] Building example for PLATFORM_WEB (Host: POSIX)\n", GetFileNameWithoutExt(inFileName)); #endif system(TextFormat("make -C %s -f Makefile.Web %s/%s PLATFORM=PLATFORM_WEB -B", exBasePath, exCategory, exName)); - + // Update generated .html metadata LOG("INFO: [%s] Updating HTML Metadata...\n", TextFormat("%s.html", exName)); UpdateWebMetadata(TextFormat("%s/%s/%s.html", exBasePath, exCategory, exName), @@ -1886,11 +1886,11 @@ int main(int argc, char *argv[]) printf(" test : Build and Test example for Desktop and Web platforms\n"); printf(" validate : Validate examples collection, generates report\n"); printf(" update : Validate and update examples collection, generates report\n\n"); - + printf("OPTIONS:\n\n"); printf(" -h, --help : Show tool version and command line usage help\n"); printf(" -v, --verbose : Verbose mode, show additional logs on processes\n"); - + printf("\nEXAMPLES:\n\n"); printf(" > rexm add shapes_custom_stars\n"); printf(" Add and updates new example provided \n\n"); From aaacda6e147031f2af0cfb6c1fd7e64d761ddb1f Mon Sep 17 00:00:00 2001 From: Wolf-SO Date: Wed, 17 Jun 2026 16:55:51 +0200 Subject: [PATCH 06/94] Remove commit message from CMakeLists.txt (#5924) Remove ambiguous footnote that would be better suited for the commit log. --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ca29ce0d6..637927400 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,4 @@ cmake_minimum_required(VERSION 3.22) -#this change avoid the warning that appear when we include raylib using Cmake fatch content project(raylib) # Avoid excessive expansion of variables in conditionals. In particular, if From 87a6e9693c54e4611b539c95138fcdc1688cd22f Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 19 Jun 2026 12:27:02 +0200 Subject: [PATCH 07/94] Format tweaks --- src/platforms/rcore_desktop_rgfw.c | 60 ++++----- src/platforms/rcore_desktop_win32.c | 188 +++++++++++++-------------- src/platforms/rcore_web_emscripten.c | 2 +- src/raudio.c | 2 +- src/raymath.h | 12 +- src/rmodels.c | 2 +- src/rtext.c | 4 +- 7 files changed, 136 insertions(+), 134 deletions(-) diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index f6b269a1d..211917359 100644 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -462,20 +462,22 @@ void RemapMouseToTouch(int touchAction); // --------------------------------------------------------------------------------- // RGFW Callbacks (instead of the older polling) // --------------------------------------------------------------------------------- -static void RGFW_cb_mousenotifyfunc(const RGFW_event* e) +static void RGFW_cb_mousenotifyfunc(const RGFW_event *e) { if (e->common.win != platform.window) return; CORE.Input.Mouse.cursorOnScreen = e->mouse.inWindow; } -// static void RGFW_cb_windowclosefunc(const RGFW_event* e) -// { -// if (e->common.win != platform.window) return; +/* +static void RGFW_cb_windowclosefunc(const RGFW_event *e) +{ + if (e->common.win != platform.window) return; -// // we don't want to close here. raylib handles it -// // RGFW_window_setShouldClose(platform.window, true); -// } -static void RGFW_cb_dropfunc(const RGFW_event* e) + // Don't want to close here, raylib handles it + //RGFW_window_setShouldClose(platform.window, true); +} +*/ +static void RGFW_cb_dropfunc(const RGFW_event *e) { if (e->common.win != platform.window) return; @@ -497,7 +499,7 @@ static void RGFW_cb_dropfunc(const RGFW_event* e) } else TRACELOG(LOG_WARNING, "FILE: Maximum drag and drop files at once is limited to 1024 files!"); } -static void RGFW_cb_windowresizefunc(const RGFW_event* e) +static void RGFW_cb_windowresizefunc(const RGFW_event *e) { if (e->common.win != platform.window) return; @@ -506,7 +508,7 @@ static void RGFW_cb_windowresizefunc(const RGFW_event* e) #if defined(__APPLE__) if (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_HIGHDPI)) { - RGFW_monitor* currentMonitor = RGFW_window_getMonitor(platform.window); + RGFW_monitor *currentMonitor = RGFW_window_getMonitor(platform.window); SetupViewport(platform.window->w*currentMonitor->pixelRatio, platform.window->h*currentMonitor->pixelRatio); CORE.Window.screenScale = MatrixScale(currentMonitor->pixelRatio, currentMonitor->pixelRatio, 1.0f); @@ -551,7 +553,7 @@ static void RGFW_cb_windowresizefunc(const RGFW_event* e) #if defined(GRAPHICS_API_OPENGL_SOFTWARE) #if defined(__APPLE__) - RGFW_monitor* currentMonitor = RGFW_window_getMonitor(platform.window); + RGFW_monitor *currentMonitor = RGFW_window_getMonitor(platform.window); CORE.Window.screenScale = MatrixScale(currentMonitor->pixelRatio, currentMonitor->pixelRatio, 1.0f); SetupViewport(platform.window->w*currentMonitor->pixelRatio, platform.window->h*currentMonitor->pixelRatio); @@ -585,19 +587,19 @@ static void RGFW_cb_windowresizefunc(const RGFW_event* e) } #endif } -static void RGFW_cb_windowmaximizefunc(const RGFW_event* e) +static void RGFW_cb_windowmaximizefunc(const RGFW_event *e) { if (e->common.win != platform.window) return; FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MAXIMIZED); // The window was maximized } -static void RGFW_cb_windowminimizefunc(const RGFW_event* e) +static void RGFW_cb_windowminimizefunc(const RGFW_event *e) { if (e->common.win != platform.window) return; FLAG_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED); // The window was iconified } -static void RGFW_cb_windowrestorefunc(const RGFW_event* e) +static void RGFW_cb_windowrestorefunc(const RGFW_event *e) { if (e->common.win != platform.window) return; @@ -606,14 +608,14 @@ static void RGFW_cb_windowrestorefunc(const RGFW_event* e) if (RGFW_window_isMinimized(platform.window)) FLAG_CLEAR(CORE.Window.flags, FLAG_WINDOW_MINIMIZED); // The window was restored } -static void RGFW_cb_windowmovefunc(const RGFW_event* e) +static void RGFW_cb_windowmovefunc(const RGFW_event *e) { if (e->common.win != platform.window) return; CORE.Window.position.x = platform.window->x; CORE.Window.position.y = platform.window->x; } -static void RGFW_cb_keycharfunc(const RGFW_event* e) +static void RGFW_cb_keycharfunc(const RGFW_event *e) { if (e->common.win != platform.window) return; @@ -626,14 +628,14 @@ static void RGFW_cb_keycharfunc(const RGFW_event* e) CORE.Input.Keyboard.charPressedQueueCount++; } } -static void RGFW_cb_scrollfunc(const RGFW_event* e) +static void RGFW_cb_scrollfunc(const RGFW_event *e) { if (e->common.win != platform.window) return; CORE.Input.Mouse.currentWheelMove.x += e->delta.x; CORE.Input.Mouse.currentWheelMove.y += e->delta.y; } -static void RGFW_cb_mousebuttonfunc(const RGFW_event* e) +static void RGFW_cb_mousebuttonfunc(const RGFW_event *e) { if (e->common.win != platform.window) return; @@ -658,7 +660,7 @@ static void RGFW_cb_mousebuttonfunc(const RGFW_event* e) RemapMouseToTouch(0); } } -static void RGFW_cb_mouserawmotionfunc(const RGFW_event* e) +static void RGFW_cb_mouserawmotionfunc(const RGFW_event *e) { if (!RGFW_window_isRawMouseMode(platform.window)) { @@ -686,7 +688,7 @@ static void RGFW_cb_mouserawmotionfunc(const RGFW_event* e) CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition; RemapMouseToTouch(2); } -static void RGFW_cb_mousemotionfunc(const RGFW_event* e) +static void RGFW_cb_mousemotionfunc(const RGFW_event *e) { if (RGFW_window_isRawMouseMode(platform.window)) { @@ -776,7 +778,7 @@ void ToggleFullscreen(void) CORE.Window.previousPosition.y = currentPosition.y; CORE.Window.previousScreen = CORE.Window.screen; - RGFW_monitor* currentMonitor = RGFW_window_getMonitor(platform.window); + RGFW_monitor *currentMonitor = RGFW_window_getMonitor(platform.window); RGFW_monitor_scaleToWindow(currentMonitor, platform.window); RGFW_window_setFullscreen(platform.window, 1); } @@ -921,7 +923,7 @@ void SetWindowState(unsigned int flags) } if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT)) { - RGFW_glHints* hints = RGFW_getGlobalHints_OpenGL(); + RGFW_glHints *hints = RGFW_getGlobalHints_OpenGL(); hints->samples = 4; RGFW_setGlobalHints_OpenGL(hints); } @@ -997,7 +999,7 @@ void ClearWindowState(unsigned int flags) } if (FLAG_IS_SET(flags, FLAG_MSAA_4X_HINT)) { - RGFW_glHints* hints = RGFW_getGlobalHints_OpenGL(); + RGFW_glHints *hints = RGFW_getGlobalHints_OpenGL(); hints->samples = 0; RGFW_setGlobalHints_OpenGL(hints); } @@ -1092,7 +1094,7 @@ void SetWindowSize(int width, int height) Vector2 scaleDpi = GetWindowScaleDPI(); #if defined(__APPLE__) - RGFW_monitor* currentMonitor = RGFW_window_getMonitor(platform.window); + RGFW_monitor *currentMonitor = RGFW_window_getMonitor(platform.window); CORE.Window.screenScale = MatrixScale(currentMonitor->pixelRatio, currentMonitor->pixelRatio, 1.0f); CORE.Window.render.width = CORE.Window.screen.width*currentMonitor->pixelRatio; @@ -1643,7 +1645,7 @@ void PollInputEvents(void) case GAMEPAD_AXIS_RIGHT_TRIGGER: CORE.Input.Gamepad.axisState[gamepadIndex][axis] = platform.minigamepad.gamepads[gamepadIndex].axes[gamepad_event.axis].value; - /* trigger button press when axis is all the way */ + // Trigger button press when axis is all the way int button = (axis == GAMEPAD_AXIS_LEFT_TRIGGER) ? GAMEPAD_BUTTON_LEFT_TRIGGER_2 : GAMEPAD_BUTTON_RIGHT_TRIGGER_2; int pressed = (platform.minigamepad.gamepads[gamepadIndex].axes[gamepad_event.axis].value >= 1.0f); @@ -1763,7 +1765,7 @@ int InitPlatform(void) // NOTE: Some OpenGL context attributes must be set before window creation // Check selection OpenGL version - RGFW_glHints* hints = RGFW_getGlobalHints_OpenGL(); + RGFW_glHints *hints = RGFW_getGlobalHints_OpenGL(); if (rlGetVersion() == RL_OPENGL_21) { hints->major = 2; @@ -1838,7 +1840,7 @@ int InitPlatform(void) Vector2 scaleDpi = GetWindowScaleDPI(); #if defined(__APPLE__) - RGFW_monitor* currentMonitor = RGFW_window_getMonitor(platform.window); + RGFW_monitor *currentMonitor = RGFW_window_getMonitor(platform.window); CORE.Window.screenScale = MatrixScale(currentMonitor->pixelRatio, currentMonitor->pixelRatio, 1.0f); CORE.Window.render.width = CORE.Window.screen.width*currentMonitor->pixelRatio; @@ -1856,7 +1858,7 @@ int InitPlatform(void) #if defined(GRAPHICS_API_OPENGL_SOFTWARE) // apple always scales for retina #if defined(__APPLE__) - RGFW_monitor* currentMonitor = RGFW_window_getMonitor(platform.window); + RGFW_monitor *currentMonitor = RGFW_window_getMonitor(platform.window); CORE.Window.screenScale = MatrixScale(currentMonitor->pixelRatio, currentMonitor->pixelRatio, 1.0f); CORE.Window.render.width = CORE.Window.screen.width*currentMonitor->pixelRatio; @@ -2045,7 +2047,7 @@ void RemapMouseToTouch(int touchAction) gestureEvent.pointCount = 1; // Register touch points position, only one point registered - if (touchAction == 2 /* || realTouch */) gestureEvent.position[0] = CORE.Input.Touch.position[0]; + if (touchAction == 2 /*|| realTouch*/) gestureEvent.position[0] = CORE.Input.Touch.position[0]; else gestureEvent.position[0] = GetMousePosition(); // Normalize gestureEvent.position[0] for CORE.Window.screen.width and CORE.Window.screen.height diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c index 16ac21e26..ef40caa9e 100644 --- a/src/platforms/rcore_desktop_win32.c +++ b/src/platforms/rcore_desktop_win32.c @@ -566,100 +566,100 @@ static KeyboardKey GetKeyFromWparam(WPARAM wparam) case 'X': return KEY_X; case 'Y': return KEY_Y; case 'Z': return KEY_Z; - /* case VK_LWIN: return KEY_; */ - /* case VK_RWIN: return KEY_; */ - /* case VK_APPS: return KEY_; */ - /* case VK_SLEEP: return KEY_; */ - /* case VK_NUMPAD0: return KEY_; */ - /* case VK_NUMPAD1: return KEY_; */ - /* case VK_NUMPAD2: return KEY_; */ - /* case VK_NUMPAD3: return KEY_; */ - /* case VK_NUMPAD4: return KEY_; */ - /* case VK_NUMPAD5: return KEY_; */ - /* case VK_NUMPAD6: return KEY_; */ - /* case VK_NUMPAD7: return KEY_; */ - /* case VK_NUMPAD8: return KEY_; */ - /* case VK_NUMPAD9: return KEY_; */ - /* case VK_MULTIPLY: return KEY_; */ - /* case VK_ADD: return KEY_; */ - /* case VK_SEPARATOR: return KEY_; */ - /* case VK_SUBTRACT: return KEY_; */ - /* case VK_DECIMAL: return KEY_; */ - /* case VK_DIVIDE: return KEY_; */ - /* case VK_F1: return KEY_; */ - /* case VK_F2: return KEY_; */ - /* case VK_F3: return KEY_; */ - /* case VK_F4: return KEY_; */ - /* case VK_F5: return KEY_; */ - /* case VK_F6: return KEY_; */ - /* case VK_F7: return KEY_; */ - /* case VK_F8: return KEY_; */ - /* case VK_F9: return KEY_; */ - /* case VK_F10: return KEY_; */ - /* case VK_F11: return KEY_; */ - /* case VK_F12: return KEY_; */ - /* case VK_F13: return KEY_; */ - /* case VK_F14: return KEY_; */ - /* case VK_F15: return KEY_; */ - /* case VK_F16: return KEY_; */ - /* case VK_F17: return KEY_; */ - /* case VK_F18: return KEY_; */ - /* case VK_F19: return KEY_; */ - /* case VK_F20: return KEY_; */ - /* case VK_F21: return KEY_; */ - /* case VK_F22: return KEY_; */ - /* case VK_F23: return KEY_; */ - /* case VK_F24: return KEY_; */ - /* case VK_NUMLOCK: return KEY_; */ - /* case VK_SCROLL: return KEY_; */ - /* case VK_LSHIFT: return KEY_; */ - /* case VK_RSHIFT: return KEY_; */ - /* case VK_LCONTROL: return KEY_; */ - /* case VK_RCONTROL: return KEY_; */ - /* case VK_LMENU: return KEY_; */ - /* case VK_RMENU: return KEY_; */ - /* case VK_BROWSER_BACK: return KEY_; */ - /* case VK_BROWSER_FORWARD: return KEY_; */ - /* case VK_BROWSER_REFRESH: return KEY_; */ - /* case VK_BROWSER_STOP: return KEY_; */ - /* case VK_BROWSER_SEARCH: return KEY_; */ - /* case VK_BROWSER_FAVORITES: return KEY_; */ - /* case VK_BROWSER_HOME: return KEY_; */ - /* case VK_VOLUME_MUTE: return KEY_; */ - /* case VK_VOLUME_DOWN: return KEY_; */ - /* case VK_VOLUME_UP: return KEY_; */ - /* case VK_MEDIA_NEXT_TRACK: return KEY_; */ - /* case VK_MEDIA_PREV_TRACK: return KEY_; */ - /* case VK_MEDIA_STOP: return KEY_; */ - /* case VK_MEDIA_PLAY_PAUSE: return KEY_; */ - /* case VK_LAUNCH_MAIL: return KEY_; */ - /* case VK_LAUNCH_MEDIA_SELECT: return KEY_; */ - /* case VK_LAUNCH_APP1: return KEY_; */ - /* case VK_LAUNCH_APP2: return KEY_; */ - /* case VK_OEM_1: return KEY_; */ - /* case VK_OEM_PLUS: return KEY_; */ - /* case VK_OEM_COMMA: return KEY_; */ - /* case VK_OEM_MINUS: return KEY_; */ - /* case VK_OEM_PERIOD: return KEY_; */ - /* case VK_OEM_2: return KEY_; */ - /* case VK_OEM_3: return KEY_; */ - /* case VK_OEM_4: return KEY_; */ - /* case VK_OEM_5: return KEY_; */ - /* case VK_OEM_6: return KEY_; */ - /* case VK_OEM_7: return KEY_; */ - /* case VK_OEM_8: return KEY_; */ - /* case VK_OEM_102: return KEY_; */ - /* case VK_PROCESSKEY: return KEY_; */ - /* case VK_PACKET: return KEY_; */ - /* case VK_ATTN: return KEY_; */ - /* case VK_CRSEL: return KEY_; */ - /* case VK_EXSEL: return KEY_; */ - /* case VK_EREOF: return KEY_; */ - /* case VK_PLAY: return KEY_; */ - /* case VK_ZOOM: return KEY_; */ - /* case VK_NONAME: return KEY_; */ - /* case VK_PA1: return KEY_; */ - /* case VK_OEM_CLEAR: return KEY_; */ + //case VK_LWIN: return KEY_; + //case VK_RWIN: return KEY_; + //case VK_APPS: return KEY_; + //case VK_SLEEP: return KEY_; + //case VK_NUMPAD0: return KEY_; + //case VK_NUMPAD1: return KEY_; + //case VK_NUMPAD2: return KEY_; + //case VK_NUMPAD3: return KEY_; + //case VK_NUMPAD4: return KEY_; + //case VK_NUMPAD5: return KEY_; + //case VK_NUMPAD6: return KEY_; + //case VK_NUMPAD7: return KEY_; + //case VK_NUMPAD8: return KEY_; + //case VK_NUMPAD9: return KEY_; + //case VK_MULTIPLY: return KEY_; + //case VK_ADD: return KEY_; + //case VK_SEPARATOR: return KEY_; + //case VK_SUBTRACT: return KEY_; + //case VK_DECIMAL: return KEY_; + //case VK_DIVIDE: return KEY_; + //case VK_F1: return KEY_; + //case VK_F2: return KEY_; + //case VK_F3: return KEY_; + //case VK_F4: return KEY_; + //case VK_F5: return KEY_; + //case VK_F6: return KEY_; + //case VK_F7: return KEY_; + //case VK_F8: return KEY_; + //case VK_F9: return KEY_; + //case VK_F10: return KEY_; + //case VK_F11: return KEY_; + //case VK_F12: return KEY_; + //case VK_F13: return KEY_; + //case VK_F14: return KEY_; + //case VK_F15: return KEY_; + //case VK_F16: return KEY_; + //case VK_F17: return KEY_; + //case VK_F18: return KEY_; + //case VK_F19: return KEY_; + //case VK_F20: return KEY_; + //case VK_F21: return KEY_; + //case VK_F22: return KEY_; + //case VK_F23: return KEY_; + //case VK_F24: return KEY_; + //case VK_NUMLOCK: return KEY_; + //case VK_SCROLL: return KEY_; + //case VK_LSHIFT: return KEY_; + //case VK_RSHIFT: return KEY_; + //case VK_LCONTROL: return KEY_; + //case VK_RCONTROL: return KEY_; + //case VK_LMENU: return KEY_; + //case VK_RMENU: return KEY_; + //case VK_BROWSER_BACK: return KEY_; + //case VK_BROWSER_FORWARD: return KEY_; + //case VK_BROWSER_REFRESH: return KEY_; + //case VK_BROWSER_STOP: return KEY_; + //case VK_BROWSER_SEARCH: return KEY_; + //case VK_BROWSER_FAVORITES: return KEY_; + //case VK_BROWSER_HOME: return KEY_; + //case VK_VOLUME_MUTE: return KEY_; + //case VK_VOLUME_DOWN: return KEY_; + //case VK_VOLUME_UP: return KEY_; + //case VK_MEDIA_NEXT_TRACK: return KEY_; + //case VK_MEDIA_PREV_TRACK: return KEY_; + //case VK_MEDIA_STOP: return KEY_; + //case VK_MEDIA_PLAY_PAUSE: return KEY_; + //case VK_LAUNCH_MAIL: return KEY_; + //case VK_LAUNCH_MEDIA_SELECT: return KEY_; + //case VK_LAUNCH_APP1: return KEY_; + //case VK_LAUNCH_APP2: return KEY_; + //case VK_OEM_1: return KEY_; + //case VK_OEM_PLUS: return KEY_; + //case VK_OEM_COMMA: return KEY_; + //case VK_OEM_MINUS: return KEY_; + //case VK_OEM_PERIOD: return KEY_; + //case VK_OEM_2: return KEY_; + //case VK_OEM_3: return KEY_; + //case VK_OEM_4: return KEY_; + //case VK_OEM_5: return KEY_; + //case VK_OEM_6: return KEY_; + //case VK_OEM_7: return KEY_; + //case VK_OEM_8: return KEY_; + //case VK_OEM_102: return KEY_; + //case VK_PROCESSKEY: return KEY_; + //case VK_PACKET: return KEY_; + //case VK_ATTN: return KEY_; + //case VK_CRSEL: return KEY_; + //case VK_EXSEL: return KEY_; + //case VK_EREOF: return KEY_; + //case VK_PLAY: return KEY_; + //case VK_ZOOM: return KEY_; + //case VK_NONAME: return KEY_; + //case VK_PA1: return KEY_; + //case VK_OEM_CLEAR: return KEY_; default: return KEY_NULL; } } diff --git a/src/platforms/rcore_web_emscripten.c b/src/platforms/rcore_web_emscripten.c index 71388e19b..ff78ac547 100644 --- a/src/platforms/rcore_web_emscripten.c +++ b/src/platforms/rcore_web_emscripten.c @@ -633,7 +633,7 @@ void SetWindowSize(int width, int height) // When resizing the canvas, several elements must be considered: // - CSS canvas size: Web layout size, logical pixels // - Canvas contained framebuffer resolution - // * Browser monitor, device pixel ratio (HighDPI) + // - Browser monitor, device pixel ratio (HighDPI) double canvasCssWidth = 0.0; double canvasCssHeight = 0.0; diff --git a/src/raudio.c b/src/raudio.c index 7963eb33d..094ea7533 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -344,7 +344,7 @@ typedef enum { // Audio buffer struct struct rAudioBuffer { ma_data_converter converter; // Audio data converter - unsigned char* converterResidual; // Cached residual input frames for use by the converter + unsigned char *converterResidual; // Cached residual input frames for use by the converter unsigned int converterResidualCount; // The number of valid frames sitting in converterResidual AudioCallback callback; // Audio buffer callback for buffer filling on audio threads diff --git a/src/raymath.h b/src/raymath.h index 4751cf00e..ff6bb8d00 100644 --- a/src/raymath.h +++ b/src/raymath.h @@ -2714,13 +2714,13 @@ RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotatio stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].y)); stabilizer = fmaxf(stabilizer, fabsf(matColumns[i].z)); } - matColumns[0] = Vector3Scale(matColumns[0], 1.0f / stabilizer); - matColumns[1] = Vector3Scale(matColumns[1], 1.0f / stabilizer); - matColumns[2] = Vector3Scale(matColumns[2], 1.0f / stabilizer); + matColumns[0] = Vector3Scale(matColumns[0], 1.0f/stabilizer); + matColumns[1] = Vector3Scale(matColumns[1], 1.0f/stabilizer); + matColumns[2] = Vector3Scale(matColumns[2], 1.0f/stabilizer); // X Scale scl.x = Vector3Length(matColumns[0]); - if (scl.x > eps) matColumns[0] = Vector3Scale(matColumns[0], 1.0f / scl.x); + if (scl.x > eps) matColumns[0] = Vector3Scale(matColumns[0], 1.0f/scl.x); // Compute XY shear and make col2 orthogonal shear[0] = Vector3DotProduct(matColumns[0], matColumns[1]); @@ -2730,7 +2730,7 @@ RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotatio scl.y = Vector3Length(matColumns[1]); if (scl.y > eps) { - matColumns[1] = Vector3Scale(matColumns[1], 1.0f / scl.y); + matColumns[1] = Vector3Scale(matColumns[1], 1.0f/scl.y); shear[0] /= scl.y; // Correct XY shear } @@ -2744,7 +2744,7 @@ RMAPI void MatrixDecompose(Matrix mat, Vector3 *translation, Quaternion *rotatio scl.z = Vector3Length(matColumns[2]); if (scl.z > eps) { - matColumns[2] = Vector3Scale(matColumns[2], 1.0f / scl.z); + matColumns[2] = Vector3Scale(matColumns[2], 1.0f/scl.z); shear[1] /= scl.z; // Correct XZ shear shear[2] /= scl.z; // Correct YZ shear } diff --git a/src/rmodels.c b/src/rmodels.c index 21f69c92e..3198e47a4 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -7212,7 +7212,7 @@ static Model LoadM3D(const char *fileName) return model; } -#define M3D_ANIMDELAY 17 // Animation frames delay, (~1000 ms/60 FPS = 16.666666* ms) +#define M3D_ANIMDELAY 17 // Animation frames delay, (~1000 ms/60 FPS = 16.666666 ms) // Load M3D animation data static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCount) diff --git a/src/rtext.c b/src/rtext.c index 75a73b813..ae28c2f98 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -947,8 +947,8 @@ Image GenImageFontAtlas(const GlyphInfo *glyphs, Rectangle **glyphRecs, int glyp // Security fix: check both lower and upper bounds if (destX >= 0 && destX < atlas.width && destY >= 0 && destY < atlas.height) { - ((unsigned char *)atlas.data)[destY * atlas.width + destX] = - ((unsigned char *)glyphs[i].image.data)[y * glyphs[i].image.width + x]; + ((unsigned char *)atlas.data)[destY*atlas.width + destX] = + ((unsigned char *)glyphs[i].image.data)[y*glyphs[i].image.width + x]; } } } From db0870f31ff10f3eed6796c5be3337a0a20d48f5 Mon Sep 17 00:00:00 2001 From: ahmedqarmout2 Date: Fri, 19 Jun 2026 17:09:30 -0400 Subject: [PATCH 08/94] Update supported version for Jai to 6.0 (#5928) Update supported version for Jai to 6.0 --- BINDINGS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BINDINGS.md b/BINDINGS.md index 7c393593c..f528c892a 100644 --- a/BINDINGS.md +++ b/BINDINGS.md @@ -103,7 +103,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers | [Raylib.lean](https://github.com/KislyjKisel/Raylib.lean) | **5.5-dev** | [Lean4](https://lean-lang.org) | BSD-3-Clause | | [raylib-cobol](https://codeberg.org/glowiak/raylib-cobol) | **auto** | [COBOL](https://gnucobol.sourceforge.io) | Public domain | | [raylib-apl](https://github.com/Brian-ED/raylib-apl) | **5.0** | [Dyalog APL](https://www.dyalog.com/) | MIT | -| [raylib-jai](https://github.com/ahmedqarmout2/raylib-jai) | **5.5** | [Jai](https://github.com/BSVino/JaiPrimer/blob/master/JaiPrimer.md) | MIT | +| [raylib-jai](https://github.com/ahmedqarmout2/raylib-jai) | **6.0** | [Jai](https://github.com/BSVino/JaiPrimer/blob/master/JaiPrimer.md) | MIT | | [fnl-raylib](https://github.com/0riginaln0/fnl-raylib) | **5.5** | [Fennel](https://fennel-lang.org/) | MIT | | [Rayua](https://github.com/uiua-lang/rayua) | **5.5** | [Uiua](https://www.uiua.org/) | **???** | | [Target](https://github.com/FinnDemonCat/Target/tree/main/libs/raylib) | **5.5** | [Dart](https://dart.dev/) | Apache-2.0 license | From b00e465debacac39c9a5510acd57a3a459734403 Mon Sep 17 00:00:00 2001 From: Juan Ferreras Date: Mon, 22 Jun 2026 19:55:08 -0300 Subject: [PATCH 09/94] Implemented JS output format. (#5929) --- tools/rlparser/output/raylib_api.js | 8525 +++++++++++++++++++++++++++ tools/rlparser/rlparser.c | 165 +- 2 files changed, 8685 insertions(+), 5 deletions(-) create mode 100644 tools/rlparser/output/raylib_api.js diff --git a/tools/rlparser/output/raylib_api.js b/tools/rlparser/output/raylib_api.js new file mode 100644 index 000000000..90008764f --- /dev/null +++ b/tools/rlparser/output/raylib_api.js @@ -0,0 +1,8525 @@ +export default { + defines: [ + { + name: "RAYLIB_H", + type: "GUARD", + value: "", + description: "" + }, + { + name: "RAYLIB_VERSION_MAJOR", + type: "INT", + value: 6, + description: "" + }, + { + name: "RAYLIB_VERSION_MINOR", + type: "INT", + value: 1, + description: "" + }, + { + name: "RAYLIB_VERSION_PATCH", + type: "INT", + value: 0, + description: "" + }, + { + name: "RAYLIB_VERSION", + type: "STRING", + value: "6.1-dev", + description: "" + }, + { + name: "__declspec(x)", + type: "MACRO", + value: "__attribute__((x))", + description: "" + }, + { + name: "RLAPI", + type: "UNKNOWN", + value: "__declspec(dllexport)", + description: "Building the library as a Win32 shared library (.dll)" + }, + { + name: "PI", + type: "FLOAT", + value: 3.14159265358979323846, + description: "" + }, + { + name: "DEG2RAD", + type: "FLOAT_MATH", + value: "(PI/180.0f)", + description: "" + }, + { + name: "RAD2DEG", + type: "FLOAT_MATH", + value: "(180.0f/PI)", + description: "" + }, + { + name: "RL_MALLOC(sz)", + type: "MACRO", + value: "malloc(sz)", + description: "" + }, + { + name: "RL_CALLOC(n,sz)", + type: "MACRO", + value: "calloc(n,sz)", + description: "" + }, + { + name: "RL_REALLOC(ptr,sz)", + type: "MACRO", + value: "realloc(ptr,sz)", + description: "" + }, + { + name: "RL_FREE(ptr)", + type: "MACRO", + value: "free(ptr)", + description: "" + }, + { + name: "CLITERAL(type)", + type: "MACRO", + value: "type", + description: "" + }, + { + name: "RL_COLOR_TYPE", + type: "GUARD", + value: "", + description: "" + }, + { + name: "RL_RECTANGLE_TYPE", + type: "GUARD", + value: "", + description: "" + }, + { + name: "RL_VECTOR2_TYPE", + type: "GUARD", + value: "", + description: "" + }, + { + name: "RL_VECTOR3_TYPE", + type: "GUARD", + value: "", + description: "" + }, + { + name: "RL_VECTOR4_TYPE", + type: "GUARD", + value: "", + description: "" + }, + { + name: "RL_QUATERNION_TYPE", + type: "GUARD", + value: "", + description: "" + }, + { + name: "RL_MATRIX_TYPE", + type: "GUARD", + value: "", + description: "" + }, + { + name: "LIGHTGRAY", + type: "COLOR", + value: "CLITERAL(Color){ 200, 200, 200, 255 }", + description: "Light Gray" + }, + { + name: "GRAY", + type: "COLOR", + value: "CLITERAL(Color){ 130, 130, 130, 255 }", + description: "Gray" + }, + { + name: "DARKGRAY", + type: "COLOR", + value: "CLITERAL(Color){ 80, 80, 80, 255 }", + description: "Dark Gray" + }, + { + name: "YELLOW", + type: "COLOR", + value: "CLITERAL(Color){ 253, 249, 0, 255 }", + description: "Yellow" + }, + { + name: "GOLD", + type: "COLOR", + value: "CLITERAL(Color){ 255, 203, 0, 255 }", + description: "Gold" + }, + { + name: "ORANGE", + type: "COLOR", + value: "CLITERAL(Color){ 255, 161, 0, 255 }", + description: "Orange" + }, + { + name: "PINK", + type: "COLOR", + value: "CLITERAL(Color){ 255, 109, 194, 255 }", + description: "Pink" + }, + { + name: "RED", + type: "COLOR", + value: "CLITERAL(Color){ 230, 41, 55, 255 }", + description: "Red" + }, + { + name: "MAROON", + type: "COLOR", + value: "CLITERAL(Color){ 190, 33, 55, 255 }", + description: "Maroon" + }, + { + name: "GREEN", + type: "COLOR", + value: "CLITERAL(Color){ 0, 228, 48, 255 }", + description: "Green" + }, + { + name: "LIME", + type: "COLOR", + value: "CLITERAL(Color){ 0, 158, 47, 255 }", + description: "Lime" + }, + { + name: "DARKGREEN", + type: "COLOR", + value: "CLITERAL(Color){ 0, 117, 44, 255 }", + description: "Dark Green" + }, + { + name: "SKYBLUE", + type: "COLOR", + value: "CLITERAL(Color){ 102, 191, 255, 255 }", + description: "Sky Blue" + }, + { + name: "BLUE", + type: "COLOR", + value: "CLITERAL(Color){ 0, 121, 241, 255 }", + description: "Blue" + }, + { + name: "DARKBLUE", + type: "COLOR", + value: "CLITERAL(Color){ 0, 82, 172, 255 }", + description: "Dark Blue" + }, + { + name: "PURPLE", + type: "COLOR", + value: "CLITERAL(Color){ 200, 122, 255, 255 }", + description: "Purple" + }, + { + name: "VIOLET", + type: "COLOR", + value: "CLITERAL(Color){ 135, 60, 190, 255 }", + description: "Violet" + }, + { + name: "DARKPURPLE", + type: "COLOR", + value: "CLITERAL(Color){ 112, 31, 126, 255 }", + description: "Dark Purple" + }, + { + name: "BEIGE", + type: "COLOR", + value: "CLITERAL(Color){ 211, 176, 131, 255 }", + description: "Beige" + }, + { + name: "BROWN", + type: "COLOR", + value: "CLITERAL(Color){ 127, 106, 79, 255 }", + description: "Brown" + }, + { + name: "DARKBROWN", + type: "COLOR", + value: "CLITERAL(Color){ 76, 63, 47, 255 }", + description: "Dark Brown" + }, + { + name: "WHITE", + type: "COLOR", + value: "CLITERAL(Color){ 255, 255, 255, 255 }", + description: "White" + }, + { + name: "BLACK", + type: "COLOR", + value: "CLITERAL(Color){ 0, 0, 0, 255 }", + description: "Black" + }, + { + name: "BLANK", + type: "COLOR", + value: "CLITERAL(Color){ 0, 0, 0, 0 }", + description: "Blank (Transparent)" + }, + { + name: "MAGENTA", + type: "COLOR", + value: "CLITERAL(Color){ 255, 0, 255, 255 }", + description: "Magenta" + }, + { + name: "RAYWHITE", + type: "COLOR", + value: "CLITERAL(Color){ 245, 245, 245, 255 }", + description: "My own White (raylib logo)" + }, + { + name: "RL_BOOL_TYPE", + type: "GUARD", + value: "", + description: "" + }, + { + name: "MOUSE_LEFT_BUTTON", + type: "UNKNOWN", + value: "MOUSE_BUTTON_LEFT", + description: "" + }, + { + name: "MOUSE_RIGHT_BUTTON", + type: "UNKNOWN", + value: "MOUSE_BUTTON_RIGHT", + description: "" + }, + { + name: "MOUSE_MIDDLE_BUTTON", + type: "UNKNOWN", + value: "MOUSE_BUTTON_MIDDLE", + description: "" + }, + { + name: "MATERIAL_MAP_DIFFUSE", + type: "UNKNOWN", + value: "MATERIAL_MAP_ALBEDO", + description: "" + }, + { + name: "MATERIAL_MAP_SPECULAR", + type: "UNKNOWN", + value: "MATERIAL_MAP_METALNESS", + description: "" + }, + { + name: "SHADER_LOC_MAP_DIFFUSE", + type: "UNKNOWN", + value: "SHADER_LOC_MAP_ALBEDO", + description: "" + }, + { + name: "SHADER_LOC_MAP_SPECULAR", + type: "UNKNOWN", + value: "SHADER_LOC_MAP_METALNESS", + description: "" + }, + { + name: "GetMouseRay", + type: "UNKNOWN", + value: "GetScreenToWorldRay", + description: "Compatibility hack for previous raylib versions" + } + ], + structs: [ + { + name: "Vector2", + description: "Vector2, 2 components", + fields: [ + { + type: "float", + name: "x", + description: "Vector x component" + }, + { + type: "float", + name: "y", + description: "Vector y component" + } + ] + }, + { + name: "Vector3", + description: "Vector3, 3 components", + fields: [ + { + type: "float", + name: "x", + description: "Vector x component" + }, + { + type: "float", + name: "y", + description: "Vector y component" + }, + { + type: "float", + name: "z", + description: "Vector z component" + } + ] + }, + { + name: "Vector4", + description: "Vector4, 4 components", + fields: [ + { + type: "float", + name: "x", + description: "Vector x component" + }, + { + type: "float", + name: "y", + description: "Vector y component" + }, + { + type: "float", + name: "z", + description: "Vector z component" + }, + { + type: "float", + name: "w", + description: "Vector w component" + } + ] + }, + { + name: "Matrix", + description: "Matrix, 4x4 components, column major, OpenGL style, right-handed", + fields: [ + { + type: "float", + name: "m0", + description: "Matrix first row (4 components)" + }, + { + type: "float", + name: "m4", + description: "Matrix first row (4 components)" + }, + { + type: "float", + name: "m8", + description: "Matrix first row (4 components)" + }, + { + type: "float", + name: "m12", + description: "Matrix first row (4 components)" + }, + { + type: "float", + name: "m1", + description: "Matrix second row (4 components)" + }, + { + type: "float", + name: "m5", + description: "Matrix second row (4 components)" + }, + { + type: "float", + name: "m9", + description: "Matrix second row (4 components)" + }, + { + type: "float", + name: "m13", + description: "Matrix second row (4 components)" + }, + { + type: "float", + name: "m2", + description: "Matrix third row (4 components)" + }, + { + type: "float", + name: "m6", + description: "Matrix third row (4 components)" + }, + { + type: "float", + name: "m10", + description: "Matrix third row (4 components)" + }, + { + type: "float", + name: "m14", + description: "Matrix third row (4 components)" + }, + { + type: "float", + name: "m3", + description: "Matrix fourth row (4 components)" + }, + { + type: "float", + name: "m7", + description: "Matrix fourth row (4 components)" + }, + { + type: "float", + name: "m11", + description: "Matrix fourth row (4 components)" + }, + { + type: "float", + name: "m15", + description: "Matrix fourth row (4 components)" + } + ] + }, + { + name: "Color", + description: "Color, 4 components, R8G8B8A8 (32bit)", + fields: [ + { + type: "unsigned char", + name: "r", + description: "Color red value" + }, + { + type: "unsigned char", + name: "g", + description: "Color green value" + }, + { + type: "unsigned char", + name: "b", + description: "Color blue value" + }, + { + type: "unsigned char", + name: "a", + description: "Color alpha value" + } + ] + }, + { + name: "Rectangle", + description: "Rectangle, 4 components", + fields: [ + { + type: "float", + name: "x", + description: "Rectangle top-left corner position x" + }, + { + type: "float", + name: "y", + description: "Rectangle top-left corner position y" + }, + { + type: "float", + name: "width", + description: "Rectangle width" + }, + { + type: "float", + name: "height", + description: "Rectangle height" + } + ] + }, + { + name: "Image", + description: "Image, pixel data stored in CPU memory (RAM)", + fields: [ + { + type: "void *", + name: "data", + description: "Image raw data" + }, + { + type: "int", + name: "width", + description: "Image base width" + }, + { + type: "int", + name: "height", + description: "Image base height" + }, + { + type: "int", + name: "mipmaps", + description: "Mipmap levels, 1 by default" + }, + { + type: "int", + name: "format", + description: "Data format (PixelFormat type)" + } + ] + }, + { + name: "Texture", + description: "Texture, tex data stored in GPU memory (VRAM)", + fields: [ + { + type: "unsigned int", + name: "id", + description: "OpenGL texture id" + }, + { + type: "int", + name: "width", + description: "Texture base width" + }, + { + type: "int", + name: "height", + description: "Texture base height" + }, + { + type: "int", + name: "mipmaps", + description: "Mipmap levels, 1 by default" + }, + { + type: "int", + name: "format", + description: "Data format (PixelFormat type)" + } + ] + }, + { + name: "RenderTexture", + description: "RenderTexture, fbo for texture rendering", + fields: [ + { + type: "unsigned int", + name: "id", + description: "OpenGL framebuffer object id" + }, + { + type: "Texture", + name: "texture", + description: "Color buffer attachment texture" + }, + { + type: "Texture", + name: "depth", + description: "Depth buffer attachment texture" + } + ] + }, + { + name: "NPatchInfo", + description: "NPatchInfo, n-patch layout info", + fields: [ + { + type: "Rectangle", + name: "source", + description: "Texture source rectangle" + }, + { + type: "int", + name: "left", + description: "Left border offset" + }, + { + type: "int", + name: "top", + description: "Top border offset" + }, + { + type: "int", + name: "right", + description: "Right border offset" + }, + { + type: "int", + name: "bottom", + description: "Bottom border offset" + }, + { + type: "int", + name: "layout", + description: "Layout of the n-patch: 3x3, 1x3 or 3x1" + } + ] + }, + { + name: "GlyphInfo", + description: "GlyphInfo, font characters glyphs info", + fields: [ + { + type: "int", + name: "value", + description: "Character value (Unicode)" + }, + { + type: "int", + name: "offsetX", + description: "Character offset X when drawing" + }, + { + type: "int", + name: "offsetY", + description: "Character offset Y when drawing" + }, + { + type: "int", + name: "advanceX", + description: "Character advance position X" + }, + { + type: "Image", + name: "image", + description: "Character image data" + } + ] + }, + { + name: "Font", + description: "Font, font texture and GlyphInfo array data", + fields: [ + { + type: "int", + name: "baseSize", + description: "Base size (default chars height)" + }, + { + type: "int", + name: "glyphCount", + description: "Number of glyph characters" + }, + { + type: "int", + name: "glyphPadding", + description: "Padding around the glyph characters" + }, + { + type: "Texture2D", + name: "texture", + description: "Texture atlas containing the glyphs" + }, + { + type: "Rectangle *", + name: "recs", + description: "Rectangles in texture for the glyphs" + }, + { + type: "GlyphInfo *", + name: "glyphs", + description: "Glyphs info data" + } + ] + }, + { + name: "Camera3D", + description: "Camera, defines position/orientation in 3d space", + fields: [ + { + type: "Vector3", + name: "position", + description: "Camera position" + }, + { + type: "Vector3", + name: "target", + description: "Camera target it looks-at" + }, + { + type: "Vector3", + name: "up", + description: "Camera up vector (rotation over its axis)" + }, + { + type: "float", + name: "fovy", + description: "Camera field-of-view aperture in Y (degrees) in perspective, used as near plane height in world units in orthographic" + }, + { + type: "int", + name: "projection", + description: "Camera projection: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC" + } + ] + }, + { + name: "Camera2D", + description: "Camera2D, defines position/orientation in 2d space", + fields: [ + { + type: "Vector2", + name: "offset", + description: "Camera offset (screen space offset from window origin)" + }, + { + type: "Vector2", + name: "target", + description: "Camera target (world space target point that is mapped to screen space offset)" + }, + { + type: "float", + name: "rotation", + description: "Camera rotation in degrees (pivots around target)" + }, + { + type: "float", + name: "zoom", + description: "Camera zoom (scaling around target), must not be set to 0, set to 1.0f for no scale" + } + ] + }, + { + name: "Mesh", + description: "Mesh, vertex data and vao/vbo", + fields: [ + { + type: "int", + name: "vertexCount", + description: "Number of vertices stored in arrays" + }, + { + type: "int", + name: "triangleCount", + description: "Number of triangles stored (indexed or not)" + }, + { + type: "float *", + name: "vertices", + description: "Vertex position (XYZ - 3 components per vertex) (shader-location = 0)" + }, + { + type: "float *", + name: "texcoords", + description: "Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)" + }, + { + type: "float *", + name: "texcoords2", + description: "Vertex texture second coordinates (UV - 2 components per vertex) (shader-location = 5)" + }, + { + type: "float *", + name: "normals", + description: "Vertex normals (XYZ - 3 components per vertex) (shader-location = 2)" + }, + { + type: "float *", + name: "tangents", + description: "Vertex tangents (XYZW - 4 components per vertex) (shader-location = 4)" + }, + { + type: "unsigned char *", + name: "colors", + description: "Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)" + }, + { + type: "unsigned short *", + name: "indices", + description: "Vertex indices (in case vertex data comes indexed)" + }, + { + type: "int", + name: "boneCount", + description: "Number of bones (MAX: 256 bones)" + }, + { + type: "unsigned char *", + name: "boneIndices", + description: "Vertex bone indices, up to 4 bones influence by vertex (skinning) (shader-location = 6)" + }, + { + type: "float *", + name: "boneWeights", + description: "Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7)" + }, + { + type: "float *", + name: "animVertices", + description: "Animated vertex positions (after bones transformations)" + }, + { + type: "float *", + name: "animNormals", + description: "Animated normals (after bones transformations)" + }, + { + type: "unsigned int", + name: "vaoId", + description: "OpenGL Vertex Array Object id" + }, + { + type: "unsigned int *", + name: "vboId", + description: "OpenGL Vertex Buffer Objects id (default vertex data)" + } + ] + }, + { + name: "Shader", + description: "Shader", + fields: [ + { + type: "unsigned int", + name: "id", + description: "Shader program id" + }, + { + type: "int *", + name: "locs", + description: "Shader locations array (RL_MAX_SHADER_LOCATIONS)" + } + ] + }, + { + name: "MaterialMap", + description: "MaterialMap", + fields: [ + { + type: "Texture2D", + name: "texture", + description: "Material map texture" + }, + { + type: "Color", + name: "color", + description: "Material map color" + }, + { + type: "float", + name: "value", + description: "Material map value" + } + ] + }, + { + name: "Material", + description: "Material, includes shader and maps", + fields: [ + { + type: "Shader", + name: "shader", + description: "Material shader" + }, + { + type: "MaterialMap *", + name: "maps", + description: "Material maps array (MAX_MATERIAL_MAPS)" + }, + { + type: "float[4]", + name: "params", + description: "Material generic parameters (if required)" + } + ] + }, + { + name: "Transform", + description: "Transform, vertex transformation data", + fields: [ + { + type: "Vector3", + name: "translation", + description: "Translation" + }, + { + type: "Quaternion", + name: "rotation", + description: "Rotation" + }, + { + type: "Vector3", + name: "scale", + description: "Scale" + } + ] + }, + { + name: "BoneInfo", + description: "Bone, skeletal animation bone", + fields: [ + { + type: "char[32]", + name: "name", + description: "Bone name" + }, + { + type: "int", + name: "parent", + description: "Bone parent" + } + ] + }, + { + name: "ModelSkeleton", + description: "Skeleton, animation bones hierarchy", + fields: [ + { + type: "int", + name: "boneCount", + description: "Number of bones" + }, + { + type: "BoneInfo *", + name: "bones", + description: "Bones information (skeleton)" + }, + { + type: "ModelAnimPose", + name: "bindPose", + description: "Bones base transformation (Transform[])" + } + ] + }, + { + name: "Model", + description: "Model, meshes, materials and animation data", + fields: [ + { + type: "Matrix", + name: "transform", + description: "Local transform matrix" + }, + { + type: "int", + name: "meshCount", + description: "Number of meshes" + }, + { + type: "int", + name: "materialCount", + description: "Number of materials" + }, + { + type: "Mesh *", + name: "meshes", + description: "Meshes array" + }, + { + type: "Material *", + name: "materials", + description: "Materials array" + }, + { + type: "int *", + name: "meshMaterial", + description: "Mesh material number" + }, + { + type: "ModelSkeleton", + name: "skeleton", + description: "Skeleton for animation" + }, + { + type: "ModelAnimPose", + name: "currentPose", + description: "Current animation pose (Transform[])" + }, + { + type: "Matrix *", + name: "boneMatrices", + description: "Bones animated transformation matrices" + } + ] + }, + { + name: "ModelAnimation", + description: "ModelAnimation, contains a full animation sequence", + fields: [ + { + type: "char[32]", + name: "name", + description: "Animation name" + }, + { + type: "int", + name: "boneCount", + description: "Number of bones (per pose)" + }, + { + type: "int", + name: "keyframeCount", + description: "Number of animation key frames" + }, + { + type: "ModelAnimPose *", + name: "keyframePoses", + description: "Animation sequence keyframe poses [keyframe][pose]" + } + ] + }, + { + name: "Ray", + description: "Ray, ray for raycasting", + fields: [ + { + type: "Vector3", + name: "position", + description: "Ray position (origin)" + }, + { + type: "Vector3", + name: "direction", + description: "Ray direction (normalized)" + } + ] + }, + { + name: "RayCollision", + description: "RayCollision, ray hit information", + fields: [ + { + type: "bool", + name: "hit", + description: "Did the ray hit something?" + }, + { + type: "float", + name: "distance", + description: "Distance to the nearest hit" + }, + { + type: "Vector3", + name: "point", + description: "Point of the nearest hit" + }, + { + type: "Vector3", + name: "normal", + description: "Surface normal of hit" + } + ] + }, + { + name: "BoundingBox", + description: "BoundingBox", + fields: [ + { + type: "Vector3", + name: "min", + description: "Minimum vertex box-corner" + }, + { + type: "Vector3", + name: "max", + description: "Maximum vertex box-corner" + } + ] + }, + { + name: "Wave", + description: "Wave, audio wave data", + fields: [ + { + type: "unsigned int", + name: "frameCount", + description: "Total number of frames (considering channels)" + }, + { + type: "unsigned int", + name: "sampleRate", + description: "Frequency (samples per second)" + }, + { + type: "unsigned int", + name: "sampleSize", + description: "Bit depth (bits per sample): 8, 16, 32 (24 not supported)" + }, + { + type: "unsigned int", + name: "channels", + description: "Number of channels (1-mono, 2-stereo, ...)" + }, + { + type: "void *", + name: "data", + description: "Buffer data pointer" + } + ] + }, + { + name: "AudioStream", + description: "AudioStream, custom audio stream", + fields: [ + { + type: "rAudioBuffer *", + name: "buffer", + description: "Pointer to internal data used by the audio system" + }, + { + type: "rAudioProcessor *", + name: "processor", + description: "Pointer to internal data processor, useful for audio effects" + }, + { + type: "unsigned int", + name: "sampleRate", + description: "Frequency (samples per second)" + }, + { + type: "unsigned int", + name: "sampleSize", + description: "Bit depth (bits per sample): 8, 16, 32 (24 not supported)" + }, + { + type: "unsigned int", + name: "channels", + description: "Number of channels (1-mono, 2-stereo, ...)" + } + ] + }, + { + name: "Sound", + description: "Sound", + fields: [ + { + type: "AudioStream", + name: "stream", + description: "Audio stream" + }, + { + type: "unsigned int", + name: "frameCount", + description: "Total number of frames (considering channels)" + } + ] + }, + { + name: "Music", + description: "Music, audio stream, anything longer than ~10 seconds should be streamed", + fields: [ + { + type: "AudioStream", + name: "stream", + description: "Audio stream" + }, + { + type: "unsigned int", + name: "frameCount", + description: "Total number of frames (considering channels)" + }, + { + type: "bool", + name: "looping", + description: "Music looping enable" + }, + { + type: "int", + name: "ctxType", + description: "Type of music context (audio filetype)" + }, + { + type: "void *", + name: "ctxData", + description: "Audio context data, depends on type" + } + ] + }, + { + name: "VrDeviceInfo", + description: "VrDeviceInfo, Head-Mounted-Display device parameters", + fields: [ + { + type: "int", + name: "hResolution", + description: "Horizontal resolution in pixels" + }, + { + type: "int", + name: "vResolution", + description: "Vertical resolution in pixels" + }, + { + type: "float", + name: "hScreenSize", + description: "Horizontal size in meters" + }, + { + type: "float", + name: "vScreenSize", + description: "Vertical size in meters" + }, + { + type: "float", + name: "eyeToScreenDistance", + description: "Distance between eye and display in meters" + }, + { + type: "float", + name: "lensSeparationDistance", + description: "Lens separation distance in meters" + }, + { + type: "float", + name: "interpupillaryDistance", + description: "IPD (distance between pupils) in meters" + }, + { + type: "float[4]", + name: "lensDistortionValues", + description: "Lens distortion constant parameters" + }, + { + type: "float[4]", + name: "chromaAbCorrection", + description: "Chromatic aberration correction parameters" + } + ] + }, + { + name: "VrStereoConfig", + description: "VrStereoConfig, VR stereo rendering configuration for simulator", + fields: [ + { + type: "Matrix[2]", + name: "projection", + description: "VR projection matrices (per eye)" + }, + { + type: "Matrix[2]", + name: "viewOffset", + description: "VR view offset matrices (per eye)" + }, + { + type: "float[2]", + name: "leftLensCenter", + description: "VR left lens center" + }, + { + type: "float[2]", + name: "rightLensCenter", + description: "VR right lens center" + }, + { + type: "float[2]", + name: "leftScreenCenter", + description: "VR left screen center" + }, + { + type: "float[2]", + name: "rightScreenCenter", + description: "VR right screen center" + }, + { + type: "float[2]", + name: "scale", + description: "VR distortion scale" + }, + { + type: "float[2]", + name: "scaleIn", + description: "VR distortion scale in" + } + ] + }, + { + name: "FilePathList", + description: "File path list", + fields: [ + { + type: "unsigned int", + name: "count", + description: "Filepaths entries count" + }, + { + type: "char **", + name: "paths", + description: "Filepaths entries" + } + ] + }, + { + name: "AutomationEvent", + description: "Automation event", + fields: [ + { + type: "unsigned int", + name: "frame", + description: "Event frame" + }, + { + type: "unsigned int", + name: "type", + description: "Event type (AutomationEventType)" + }, + { + type: "int[4]", + name: "params", + description: "Event parameters (if required)" + } + ] + }, + { + name: "AutomationEventList", + description: "Automation event list", + fields: [ + { + type: "unsigned int", + name: "capacity", + description: "Events max entries (MAX_AUTOMATION_EVENTS)" + }, + { + type: "unsigned int", + name: "count", + description: "Events entries count" + }, + { + type: "AutomationEvent *", + name: "events", + description: "Events entries" + } + ] + } + ], + aliases: [ + { + type: "Vector4", + name: "Quaternion", + description: "Quaternion, 4 components (Vector4 alias)" + }, + { + type: "Texture", + name: "Texture2D", + description: "Texture2D, same as Texture" + }, + { + type: "Texture", + name: "TextureCubemap", + description: "TextureCubemap, same as Texture" + }, + { + type: "RenderTexture", + name: "RenderTexture2D", + description: "RenderTexture2D, same as RenderTexture" + }, + { + type: "Camera3D", + name: "Camera", + description: "Camera type fallback, defaults to Camera3D" + }, + { + type: "Transform", + name: "*ModelAnimPose", + description: "Anim pose, an array of Transform[]" + } + ], + enums: [ + { + name: "ConfigFlags", + description: "System/Window config flags", + values: [ + { + name: "FLAG_VSYNC_HINT", + value: 64, + description: "Set to try enabling V-Sync on GPU" + }, + { + name: "FLAG_FULLSCREEN_MODE", + value: 2, + description: "Set to run program in fullscreen" + }, + { + name: "FLAG_WINDOW_RESIZABLE", + value: 4, + description: "Set to allow resizable window" + }, + { + name: "FLAG_WINDOW_UNDECORATED", + value: 8, + description: "Set to disable window decoration (frame and buttons)" + }, + { + name: "FLAG_WINDOW_HIDDEN", + value: 128, + description: "Set to hide window" + }, + { + name: "FLAG_WINDOW_MINIMIZED", + value: 512, + description: "Set to minimize window (iconify)" + }, + { + name: "FLAG_WINDOW_MAXIMIZED", + value: 1024, + description: "Set to maximize window (expanded to monitor)" + }, + { + name: "FLAG_WINDOW_UNFOCUSED", + value: 2048, + description: "Set to window non focused" + }, + { + name: "FLAG_WINDOW_TOPMOST", + value: 4096, + description: "Set to window always on top" + }, + { + name: "FLAG_WINDOW_ALWAYS_RUN", + value: 256, + description: "Set to allow windows running while minimized" + }, + { + name: "FLAG_WINDOW_TRANSPARENT", + value: 16, + description: "Set to allow transparent framebuffer" + }, + { + name: "FLAG_WINDOW_HIGHDPI", + value: 8192, + description: "Set to support HighDPI" + }, + { + name: "FLAG_WINDOW_MOUSE_PASSTHROUGH", + value: 16384, + description: "Set to support mouse passthrough, only supported when FLAG_WINDOW_UNDECORATED" + }, + { + name: "FLAG_BORDERLESS_WINDOWED_MODE", + value: 32768, + description: "Set to run program in borderless windowed mode" + }, + { + name: "FLAG_MSAA_4X_HINT", + value: 32, + description: "Set to try enabling MSAA 4X" + }, + { + name: "FLAG_INTERLACED_HINT", + value: 65536, + description: "Set to try enabling interlaced video format (for V3D)" + } + ] + }, + { + name: "TraceLogLevel", + description: "Trace log level", + values: [ + { + name: "LOG_ALL", + value: 0, + description: "Display all logs" + }, + { + name: "LOG_TRACE", + value: 1, + description: "Trace logging, intended for internal use only" + }, + { + name: "LOG_DEBUG", + value: 2, + description: "Debug logging, used for internal debugging, it should be disabled on release builds" + }, + { + name: "LOG_INFO", + value: 3, + description: "Info logging, used for program execution info" + }, + { + name: "LOG_WARNING", + value: 4, + description: "Warning logging, used on recoverable failures" + }, + { + name: "LOG_ERROR", + value: 5, + description: "Error logging, used on unrecoverable failures" + }, + { + name: "LOG_FATAL", + value: 6, + description: "Fatal logging, used to abort program: exit(EXIT_FAILURE)" + }, + { + name: "LOG_NONE", + value: 7, + description: "Disable logging" + } + ] + }, + { + name: "KeyboardKey", + description: "Keyboard keys (US keyboard layout)", + values: [ + { + name: "KEY_NULL", + value: 0, + description: "Key: NULL, used for no key pressed" + }, + { + name: "KEY_APOSTROPHE", + value: 39, + description: "Key: '" + }, + { + name: "KEY_COMMA", + value: 44, + description: "Key: ," + }, + { + name: "KEY_MINUS", + value: 45, + description: "Key: -" + }, + { + name: "KEY_PERIOD", + value: 46, + description: "Key: ." + }, + { + name: "KEY_SLASH", + value: 47, + description: "Key: /" + }, + { + name: "KEY_ZERO", + value: 48, + description: "Key: 0" + }, + { + name: "KEY_ONE", + value: 49, + description: "Key: 1" + }, + { + name: "KEY_TWO", + value: 50, + description: "Key: 2" + }, + { + name: "KEY_THREE", + value: 51, + description: "Key: 3" + }, + { + name: "KEY_FOUR", + value: 52, + description: "Key: 4" + }, + { + name: "KEY_FIVE", + value: 53, + description: "Key: 5" + }, + { + name: "KEY_SIX", + value: 54, + description: "Key: 6" + }, + { + name: "KEY_SEVEN", + value: 55, + description: "Key: 7" + }, + { + name: "KEY_EIGHT", + value: 56, + description: "Key: 8" + }, + { + name: "KEY_NINE", + value: 57, + description: "Key: 9" + }, + { + name: "KEY_SEMICOLON", + value: 59, + description: "Key: ;" + }, + { + name: "KEY_EQUAL", + value: 61, + description: "Key: =" + }, + { + name: "KEY_A", + value: 65, + description: "Key: A | a" + }, + { + name: "KEY_B", + value: 66, + description: "Key: B | b" + }, + { + name: "KEY_C", + value: 67, + description: "Key: C | c" + }, + { + name: "KEY_D", + value: 68, + description: "Key: D | d" + }, + { + name: "KEY_E", + value: 69, + description: "Key: E | e" + }, + { + name: "KEY_F", + value: 70, + description: "Key: F | f" + }, + { + name: "KEY_G", + value: 71, + description: "Key: G | g" + }, + { + name: "KEY_H", + value: 72, + description: "Key: H | h" + }, + { + name: "KEY_I", + value: 73, + description: "Key: I | i" + }, + { + name: "KEY_J", + value: 74, + description: "Key: J | j" + }, + { + name: "KEY_K", + value: 75, + description: "Key: K | k" + }, + { + name: "KEY_L", + value: 76, + description: "Key: L | l" + }, + { + name: "KEY_M", + value: 77, + description: "Key: M | m" + }, + { + name: "KEY_N", + value: 78, + description: "Key: N | n" + }, + { + name: "KEY_O", + value: 79, + description: "Key: O | o" + }, + { + name: "KEY_P", + value: 80, + description: "Key: P | p" + }, + { + name: "KEY_Q", + value: 81, + description: "Key: Q | q" + }, + { + name: "KEY_R", + value: 82, + description: "Key: R | r" + }, + { + name: "KEY_S", + value: 83, + description: "Key: S | s" + }, + { + name: "KEY_T", + value: 84, + description: "Key: T | t" + }, + { + name: "KEY_U", + value: 85, + description: "Key: U | u" + }, + { + name: "KEY_V", + value: 86, + description: "Key: V | v" + }, + { + name: "KEY_W", + value: 87, + description: "Key: W | w" + }, + { + name: "KEY_X", + value: 88, + description: "Key: X | x" + }, + { + name: "KEY_Y", + value: 89, + description: "Key: Y | y" + }, + { + name: "KEY_Z", + value: 90, + description: "Key: Z | z" + }, + { + name: "KEY_LEFT_BRACKET", + value: 91, + description: "Key: [" + }, + { + name: "KEY_BACKSLASH", + value: 92, + description: "Key: '\\'" + }, + { + name: "KEY_RIGHT_BRACKET", + value: 93, + description: "Key: ]" + }, + { + name: "KEY_GRAVE", + value: 96, + description: "Key: `" + }, + { + name: "KEY_SPACE", + value: 32, + description: "Key: Space" + }, + { + name: "KEY_ESCAPE", + value: 256, + description: "Key: Esc" + }, + { + name: "KEY_ENTER", + value: 257, + description: "Key: Enter" + }, + { + name: "KEY_TAB", + value: 258, + description: "Key: Tab" + }, + { + name: "KEY_BACKSPACE", + value: 259, + description: "Key: Backspace" + }, + { + name: "KEY_INSERT", + value: 260, + description: "Key: Ins" + }, + { + name: "KEY_DELETE", + value: 261, + description: "Key: Del" + }, + { + name: "KEY_RIGHT", + value: 262, + description: "Key: Cursor right" + }, + { + name: "KEY_LEFT", + value: 263, + description: "Key: Cursor left" + }, + { + name: "KEY_DOWN", + value: 264, + description: "Key: Cursor down" + }, + { + name: "KEY_UP", + value: 265, + description: "Key: Cursor up" + }, + { + name: "KEY_PAGE_UP", + value: 266, + description: "Key: Page up" + }, + { + name: "KEY_PAGE_DOWN", + value: 267, + description: "Key: Page down" + }, + { + name: "KEY_HOME", + value: 268, + description: "Key: Home" + }, + { + name: "KEY_END", + value: 269, + description: "Key: End" + }, + { + name: "KEY_CAPS_LOCK", + value: 280, + description: "Key: Caps lock" + }, + { + name: "KEY_SCROLL_LOCK", + value: 281, + description: "Key: Scroll down" + }, + { + name: "KEY_NUM_LOCK", + value: 282, + description: "Key: Num lock" + }, + { + name: "KEY_PRINT_SCREEN", + value: 283, + description: "Key: Print screen" + }, + { + name: "KEY_PAUSE", + value: 284, + description: "Key: Pause" + }, + { + name: "KEY_F1", + value: 290, + description: "Key: F1" + }, + { + name: "KEY_F2", + value: 291, + description: "Key: F2" + }, + { + name: "KEY_F3", + value: 292, + description: "Key: F3" + }, + { + name: "KEY_F4", + value: 293, + description: "Key: F4" + }, + { + name: "KEY_F5", + value: 294, + description: "Key: F5" + }, + { + name: "KEY_F6", + value: 295, + description: "Key: F6" + }, + { + name: "KEY_F7", + value: 296, + description: "Key: F7" + }, + { + name: "KEY_F8", + value: 297, + description: "Key: F8" + }, + { + name: "KEY_F9", + value: 298, + description: "Key: F9" + }, + { + name: "KEY_F10", + value: 299, + description: "Key: F10" + }, + { + name: "KEY_F11", + value: 300, + description: "Key: F11" + }, + { + name: "KEY_F12", + value: 301, + description: "Key: F12" + }, + { + name: "KEY_LEFT_SHIFT", + value: 340, + description: "Key: Shift left" + }, + { + name: "KEY_LEFT_CONTROL", + value: 341, + description: "Key: Control left" + }, + { + name: "KEY_LEFT_ALT", + value: 342, + description: "Key: Alt left" + }, + { + name: "KEY_LEFT_SUPER", + value: 343, + description: "Key: Super left" + }, + { + name: "KEY_RIGHT_SHIFT", + value: 344, + description: "Key: Shift right" + }, + { + name: "KEY_RIGHT_CONTROL", + value: 345, + description: "Key: Control right" + }, + { + name: "KEY_RIGHT_ALT", + value: 346, + description: "Key: Alt right" + }, + { + name: "KEY_RIGHT_SUPER", + value: 347, + description: "Key: Super right" + }, + { + name: "KEY_KB_MENU", + value: 348, + description: "Key: KB menu" + }, + { + name: "KEY_KP_0", + value: 320, + description: "Key: Keypad 0" + }, + { + name: "KEY_KP_1", + value: 321, + description: "Key: Keypad 1" + }, + { + name: "KEY_KP_2", + value: 322, + description: "Key: Keypad 2" + }, + { + name: "KEY_KP_3", + value: 323, + description: "Key: Keypad 3" + }, + { + name: "KEY_KP_4", + value: 324, + description: "Key: Keypad 4" + }, + { + name: "KEY_KP_5", + value: 325, + description: "Key: Keypad 5" + }, + { + name: "KEY_KP_6", + value: 326, + description: "Key: Keypad 6" + }, + { + name: "KEY_KP_7", + value: 327, + description: "Key: Keypad 7" + }, + { + name: "KEY_KP_8", + value: 328, + description: "Key: Keypad 8" + }, + { + name: "KEY_KP_9", + value: 329, + description: "Key: Keypad 9" + }, + { + name: "KEY_KP_DECIMAL", + value: 330, + description: "Key: Keypad ." + }, + { + name: "KEY_KP_DIVIDE", + value: 331, + description: "Key: Keypad /" + }, + { + name: "KEY_KP_MULTIPLY", + value: 332, + description: "Key: Keypad *" + }, + { + name: "KEY_KP_SUBTRACT", + value: 333, + description: "Key: Keypad -" + }, + { + name: "KEY_KP_ADD", + value: 334, + description: "Key: Keypad +" + }, + { + name: "KEY_KP_ENTER", + value: 335, + description: "Key: Keypad Enter" + }, + { + name: "KEY_KP_EQUAL", + value: 336, + description: "Key: Keypad =" + }, + { + name: "KEY_BACK", + value: 4, + description: "Key: Android back button" + }, + { + name: "KEY_MENU", + value: 5, + description: "Key: Android menu button" + }, + { + name: "KEY_VOLUME_UP", + value: 24, + description: "Key: Android volume up button" + }, + { + name: "KEY_VOLUME_DOWN", + value: 25, + description: "Key: Android volume down button" + } + ] + }, + { + name: "MouseButton", + description: "Mouse buttons", + values: [ + { + name: "MOUSE_BUTTON_LEFT", + value: 0, + description: "Mouse button left" + }, + { + name: "MOUSE_BUTTON_RIGHT", + value: 1, + description: "Mouse button right" + }, + { + name: "MOUSE_BUTTON_MIDDLE", + value: 2, + description: "Mouse button middle (pressed wheel)" + }, + { + name: "MOUSE_BUTTON_SIDE", + value: 3, + description: "Mouse button side (advanced mouse device)" + }, + { + name: "MOUSE_BUTTON_EXTRA", + value: 4, + description: "Mouse button extra (advanced mouse device)" + }, + { + name: "MOUSE_BUTTON_FORWARD", + value: 5, + description: "Mouse button forward (advanced mouse device)" + }, + { + name: "MOUSE_BUTTON_BACK", + value: 6, + description: "Mouse button back (advanced mouse device)" + } + ] + }, + { + name: "MouseCursor", + description: "Mouse cursor", + values: [ + { + name: "MOUSE_CURSOR_DEFAULT", + value: 0, + description: "Default pointer shape" + }, + { + name: "MOUSE_CURSOR_ARROW", + value: 1, + description: "Arrow shape" + }, + { + name: "MOUSE_CURSOR_IBEAM", + value: 2, + description: "Text writing cursor shape" + }, + { + name: "MOUSE_CURSOR_CROSSHAIR", + value: 3, + description: "Cross shape" + }, + { + name: "MOUSE_CURSOR_POINTING_HAND", + value: 4, + description: "Pointing hand cursor" + }, + { + name: "MOUSE_CURSOR_RESIZE_EW", + value: 5, + description: "Horizontal resize/move arrow shape" + }, + { + name: "MOUSE_CURSOR_RESIZE_NS", + value: 6, + description: "Vertical resize/move arrow shape" + }, + { + name: "MOUSE_CURSOR_RESIZE_NWSE", + value: 7, + description: "Top-left to bottom-right diagonal resize/move arrow shape" + }, + { + name: "MOUSE_CURSOR_RESIZE_NESW", + value: 8, + description: "The top-right to bottom-left diagonal resize/move arrow shape" + }, + { + name: "MOUSE_CURSOR_RESIZE_ALL", + value: 9, + description: "The omnidirectional resize/move cursor shape" + }, + { + name: "MOUSE_CURSOR_NOT_ALLOWED", + value: 10, + description: "The operation-not-allowed shape" + } + ] + }, + { + name: "GamepadButton", + description: "Gamepad buttons", + values: [ + { + name: "GAMEPAD_BUTTON_UNKNOWN", + value: 0, + description: "Unknown button, for error checking" + }, + { + name: "GAMEPAD_BUTTON_LEFT_FACE_UP", + value: 1, + description: "Gamepad left DPAD up button" + }, + { + name: "GAMEPAD_BUTTON_LEFT_FACE_RIGHT", + value: 2, + description: "Gamepad left DPAD right button" + }, + { + name: "GAMEPAD_BUTTON_LEFT_FACE_DOWN", + value: 3, + description: "Gamepad left DPAD down button" + }, + { + name: "GAMEPAD_BUTTON_LEFT_FACE_LEFT", + value: 4, + description: "Gamepad left DPAD left button" + }, + { + name: "GAMEPAD_BUTTON_RIGHT_FACE_UP", + value: 5, + description: "Gamepad right button up (i.e. PS3: Triangle, Xbox: Y)" + }, + { + name: "GAMEPAD_BUTTON_RIGHT_FACE_RIGHT", + value: 6, + description: "Gamepad right button right (i.e. PS3: Circle, Xbox: B)" + }, + { + name: "GAMEPAD_BUTTON_RIGHT_FACE_DOWN", + value: 7, + description: "Gamepad right button down (i.e. PS3: Cross, Xbox: A)" + }, + { + name: "GAMEPAD_BUTTON_RIGHT_FACE_LEFT", + value: 8, + description: "Gamepad right button left (i.e. PS3: Square, Xbox: X)" + }, + { + name: "GAMEPAD_BUTTON_LEFT_TRIGGER_1", + value: 9, + description: "Gamepad top/back trigger left (first), it could be a trailing button" + }, + { + name: "GAMEPAD_BUTTON_LEFT_TRIGGER_2", + value: 10, + description: "Gamepad top/back trigger left (second), it could be a trailing button" + }, + { + name: "GAMEPAD_BUTTON_RIGHT_TRIGGER_1", + value: 11, + description: "Gamepad top/back trigger right (first), it could be a trailing button" + }, + { + name: "GAMEPAD_BUTTON_RIGHT_TRIGGER_2", + value: 12, + description: "Gamepad top/back trigger right (second), it could be a trailing button" + }, + { + name: "GAMEPAD_BUTTON_MIDDLE_LEFT", + value: 13, + description: "Gamepad center buttons, left one (i.e. PS3: Select)" + }, + { + name: "GAMEPAD_BUTTON_MIDDLE", + value: 14, + description: "Gamepad center buttons, middle one (i.e. PS3: PS, Xbox: XBOX)" + }, + { + name: "GAMEPAD_BUTTON_MIDDLE_RIGHT", + value: 15, + description: "Gamepad center buttons, right one (i.e. PS3: Start)" + }, + { + name: "GAMEPAD_BUTTON_LEFT_THUMB", + value: 16, + description: "Gamepad joystick pressed button left" + }, + { + name: "GAMEPAD_BUTTON_RIGHT_THUMB", + value: 17, + description: "Gamepad joystick pressed button right" + } + ] + }, + { + name: "GamepadAxis", + description: "Gamepad axes", + values: [ + { + name: "GAMEPAD_AXIS_LEFT_X", + value: 0, + description: "Gamepad left stick X axis" + }, + { + name: "GAMEPAD_AXIS_LEFT_Y", + value: 1, + description: "Gamepad left stick Y axis" + }, + { + name: "GAMEPAD_AXIS_RIGHT_X", + value: 2, + description: "Gamepad right stick X axis" + }, + { + name: "GAMEPAD_AXIS_RIGHT_Y", + value: 3, + description: "Gamepad right stick Y axis" + }, + { + name: "GAMEPAD_AXIS_LEFT_TRIGGER", + value: 4, + description: "Gamepad back trigger left, pressure level: [1..-1]" + }, + { + name: "GAMEPAD_AXIS_RIGHT_TRIGGER", + value: 5, + description: "Gamepad back trigger right, pressure level: [1..-1]" + } + ] + }, + { + name: "MaterialMapIndex", + description: "Material map index", + values: [ + { + name: "MATERIAL_MAP_ALBEDO", + value: 0, + description: "Albedo material (same as: MATERIAL_MAP_DIFFUSE)" + }, + { + name: "MATERIAL_MAP_METALNESS", + value: 1, + description: "Metalness material (same as: MATERIAL_MAP_SPECULAR)" + }, + { + name: "MATERIAL_MAP_NORMAL", + value: 2, + description: "Normal material" + }, + { + name: "MATERIAL_MAP_ROUGHNESS", + value: 3, + description: "Roughness material" + }, + { + name: "MATERIAL_MAP_OCCLUSION", + value: 4, + description: "Ambient occlusion material" + }, + { + name: "MATERIAL_MAP_EMISSION", + value: 5, + description: "Emission material" + }, + { + name: "MATERIAL_MAP_HEIGHT", + value: 6, + description: "Heightmap material" + }, + { + name: "MATERIAL_MAP_CUBEMAP", + value: 7, + description: "Cubemap material (NOTE: Uses GL_TEXTURE_CUBE_MAP)" + }, + { + name: "MATERIAL_MAP_IRRADIANCE", + value: 8, + description: "Irradiance material (NOTE: Uses GL_TEXTURE_CUBE_MAP)" + }, + { + name: "MATERIAL_MAP_PREFILTER", + value: 9, + description: "Prefilter material (NOTE: Uses GL_TEXTURE_CUBE_MAP)" + }, + { + name: "MATERIAL_MAP_BRDF", + value: 10, + description: "Brdf material" + } + ] + }, + { + name: "ShaderLocationIndex", + description: "Shader location index", + values: [ + { + name: "SHADER_LOC_VERTEX_POSITION", + value: 0, + description: "Shader location: vertex attribute: position" + }, + { + name: "SHADER_LOC_VERTEX_TEXCOORD01", + value: 1, + description: "Shader location: vertex attribute: texcoord01" + }, + { + name: "SHADER_LOC_VERTEX_TEXCOORD02", + value: 2, + description: "Shader location: vertex attribute: texcoord02" + }, + { + name: "SHADER_LOC_VERTEX_NORMAL", + value: 3, + description: "Shader location: vertex attribute: normal" + }, + { + name: "SHADER_LOC_VERTEX_TANGENT", + value: 4, + description: "Shader location: vertex attribute: tangent" + }, + { + name: "SHADER_LOC_VERTEX_COLOR", + value: 5, + description: "Shader location: vertex attribute: color" + }, + { + name: "SHADER_LOC_MATRIX_MVP", + value: 6, + description: "Shader location: matrix uniform: model-view-projection" + }, + { + name: "SHADER_LOC_MATRIX_VIEW", + value: 7, + description: "Shader location: matrix uniform: view (camera transform)" + }, + { + name: "SHADER_LOC_MATRIX_PROJECTION", + value: 8, + description: "Shader location: matrix uniform: projection" + }, + { + name: "SHADER_LOC_MATRIX_MODEL", + value: 9, + description: "Shader location: matrix uniform: model (transform)" + }, + { + name: "SHADER_LOC_MATRIX_NORMAL", + value: 10, + description: "Shader location: matrix uniform: normal" + }, + { + name: "SHADER_LOC_VECTOR_VIEW", + value: 11, + description: "Shader location: vector uniform: view" + }, + { + name: "SHADER_LOC_COLOR_DIFFUSE", + value: 12, + description: "Shader location: vector uniform: diffuse color" + }, + { + name: "SHADER_LOC_COLOR_SPECULAR", + value: 13, + description: "Shader location: vector uniform: specular color" + }, + { + name: "SHADER_LOC_COLOR_AMBIENT", + value: 14, + description: "Shader location: vector uniform: ambient color" + }, + { + name: "SHADER_LOC_MAP_ALBEDO", + value: 15, + description: "Shader location: sampler2d texture: albedo (same as: SHADER_LOC_MAP_DIFFUSE)" + }, + { + name: "SHADER_LOC_MAP_METALNESS", + value: 16, + description: "Shader location: sampler2d texture: metalness (same as: SHADER_LOC_MAP_SPECULAR)" + }, + { + name: "SHADER_LOC_MAP_NORMAL", + value: 17, + description: "Shader location: sampler2d texture: normal" + }, + { + name: "SHADER_LOC_MAP_ROUGHNESS", + value: 18, + description: "Shader location: sampler2d texture: roughness" + }, + { + name: "SHADER_LOC_MAP_OCCLUSION", + value: 19, + description: "Shader location: sampler2d texture: occlusion" + }, + { + name: "SHADER_LOC_MAP_EMISSION", + value: 20, + description: "Shader location: sampler2d texture: emission" + }, + { + name: "SHADER_LOC_MAP_HEIGHT", + value: 21, + description: "Shader location: sampler2d texture: heightmap" + }, + { + name: "SHADER_LOC_MAP_CUBEMAP", + value: 22, + description: "Shader location: samplerCube texture: cubemap" + }, + { + name: "SHADER_LOC_MAP_IRRADIANCE", + value: 23, + description: "Shader location: samplerCube texture: irradiance" + }, + { + name: "SHADER_LOC_MAP_PREFILTER", + value: 24, + description: "Shader location: samplerCube texture: prefilter" + }, + { + name: "SHADER_LOC_MAP_BRDF", + value: 25, + description: "Shader location: sampler2d texture: brdf" + }, + { + name: "SHADER_LOC_VERTEX_BONEIDS", + value: 26, + description: "Shader location: vertex attribute: bone indices" + }, + { + name: "SHADER_LOC_VERTEX_BONEWEIGHTS", + value: 27, + description: "Shader location: vertex attribute: bone weights" + }, + { + name: "SHADER_LOC_MATRIX_BONETRANSFORMS", + value: 28, + description: "Shader location: matrix attribute: bone transforms (animation)" + }, + { + name: "SHADER_LOC_VERTEX_INSTANCETRANSFORM", + value: 29, + description: "Shader location: vertex attribute: instance transforms" + } + ] + }, + { + name: "ShaderUniformDataType", + description: "Shader uniform data type", + values: [ + { + name: "SHADER_UNIFORM_FLOAT", + value: 0, + description: "Shader uniform type: float" + }, + { + name: "SHADER_UNIFORM_VEC2", + value: 1, + description: "Shader uniform type: vec2 (2 float)" + }, + { + name: "SHADER_UNIFORM_VEC3", + value: 2, + description: "Shader uniform type: vec3 (3 float)" + }, + { + name: "SHADER_UNIFORM_VEC4", + value: 3, + description: "Shader uniform type: vec4 (4 float)" + }, + { + name: "SHADER_UNIFORM_INT", + value: 4, + description: "Shader uniform type: int" + }, + { + name: "SHADER_UNIFORM_IVEC2", + value: 5, + description: "Shader uniform type: ivec2 (2 int)" + }, + { + name: "SHADER_UNIFORM_IVEC3", + value: 6, + description: "Shader uniform type: ivec3 (3 int)" + }, + { + name: "SHADER_UNIFORM_IVEC4", + value: 7, + description: "Shader uniform type: ivec4 (4 int)" + }, + { + name: "SHADER_UNIFORM_UINT", + value: 8, + description: "Shader uniform type: unsigned int" + }, + { + name: "SHADER_UNIFORM_UIVEC2", + value: 9, + description: "Shader uniform type: uivec2 (2 unsigned int)" + }, + { + name: "SHADER_UNIFORM_UIVEC3", + value: 10, + description: "Shader uniform type: uivec3 (3 unsigned int)" + }, + { + name: "SHADER_UNIFORM_UIVEC4", + value: 11, + description: "Shader uniform type: uivec4 (4 unsigned int)" + }, + { + name: "SHADER_UNIFORM_SAMPLER2D", + value: 12, + description: "Shader uniform type: sampler2d" + } + ] + }, + { + name: "ShaderAttributeDataType", + description: "Shader attribute data types", + values: [ + { + name: "SHADER_ATTRIB_FLOAT", + value: 0, + description: "Shader attribute type: float" + }, + { + name: "SHADER_ATTRIB_VEC2", + value: 1, + description: "Shader attribute type: vec2 (2 float)" + }, + { + name: "SHADER_ATTRIB_VEC3", + value: 2, + description: "Shader attribute type: vec3 (3 float)" + }, + { + name: "SHADER_ATTRIB_VEC4", + value: 3, + description: "Shader attribute type: vec4 (4 float)" + } + ] + }, + { + name: "PixelFormat", + description: "Pixel formats", + values: [ + { + name: "PIXELFORMAT_UNCOMPRESSED_GRAYSCALE", + value: 1, + description: "8 bit per pixel (no alpha)" + }, + { + name: "PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA", + value: 2, + description: "8*2 bpp (2 channels)" + }, + { + name: "PIXELFORMAT_UNCOMPRESSED_R5G6B5", + value: 3, + description: "16 bpp" + }, + { + name: "PIXELFORMAT_UNCOMPRESSED_R8G8B8", + value: 4, + description: "24 bpp" + }, + { + name: "PIXELFORMAT_UNCOMPRESSED_R5G5B5A1", + value: 5, + description: "16 bpp (1 bit alpha)" + }, + { + name: "PIXELFORMAT_UNCOMPRESSED_R4G4B4A4", + value: 6, + description: "16 bpp (4 bit alpha)" + }, + { + name: "PIXELFORMAT_UNCOMPRESSED_R8G8B8A8", + value: 7, + description: "32 bpp" + }, + { + name: "PIXELFORMAT_UNCOMPRESSED_R32", + value: 8, + description: "32 bpp (1 channel - float)" + }, + { + name: "PIXELFORMAT_UNCOMPRESSED_R32G32B32", + value: 9, + description: "32*3 bpp (3 channels - float)" + }, + { + name: "PIXELFORMAT_UNCOMPRESSED_R32G32B32A32", + value: 10, + description: "32*4 bpp (4 channels - float)" + }, + { + name: "PIXELFORMAT_UNCOMPRESSED_R16", + value: 11, + description: "16 bpp (1 channel - half float)" + }, + { + name: "PIXELFORMAT_UNCOMPRESSED_R16G16B16", + value: 12, + description: "16*3 bpp (3 channels - half float)" + }, + { + name: "PIXELFORMAT_UNCOMPRESSED_R16G16B16A16", + value: 13, + description: "16*4 bpp (4 channels - half float)" + }, + { + name: "PIXELFORMAT_COMPRESSED_DXT1_RGB", + value: 14, + description: "4 bpp (no alpha)" + }, + { + name: "PIXELFORMAT_COMPRESSED_DXT1_RGBA", + value: 15, + description: "4 bpp (1 bit alpha)" + }, + { + name: "PIXELFORMAT_COMPRESSED_DXT3_RGBA", + value: 16, + description: "8 bpp" + }, + { + name: "PIXELFORMAT_COMPRESSED_DXT5_RGBA", + value: 17, + description: "8 bpp" + }, + { + name: "PIXELFORMAT_COMPRESSED_ETC1_RGB", + value: 18, + description: "4 bpp" + }, + { + name: "PIXELFORMAT_COMPRESSED_ETC2_RGB", + value: 19, + description: "4 bpp" + }, + { + name: "PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA", + value: 20, + description: "8 bpp" + }, + { + name: "PIXELFORMAT_COMPRESSED_PVRT_RGB", + value: 21, + description: "4 bpp" + }, + { + name: "PIXELFORMAT_COMPRESSED_PVRT_RGBA", + value: 22, + description: "4 bpp" + }, + { + name: "PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA", + value: 23, + description: "8 bpp" + }, + { + name: "PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA", + value: 24, + description: "2 bpp" + } + ] + }, + { + name: "TextureFilter", + description: "Texture parameters: filter mode", + values: [ + { + name: "TEXTURE_FILTER_POINT", + value: 0, + description: "No filter, pixel approximation" + }, + { + name: "TEXTURE_FILTER_BILINEAR", + value: 1, + description: "Linear filtering" + }, + { + name: "TEXTURE_FILTER_TRILINEAR", + value: 2, + description: "Trilinear filtering (linear with mipmaps)" + }, + { + name: "TEXTURE_FILTER_ANISOTROPIC_4X", + value: 3, + description: "Anisotropic filtering 4x" + }, + { + name: "TEXTURE_FILTER_ANISOTROPIC_8X", + value: 4, + description: "Anisotropic filtering 8x" + }, + { + name: "TEXTURE_FILTER_ANISOTROPIC_16X", + value: 5, + description: "Anisotropic filtering 16x" + } + ] + }, + { + name: "TextureWrap", + description: "Texture parameters: wrap mode", + values: [ + { + name: "TEXTURE_WRAP_REPEAT", + value: 0, + description: "Repeats texture in tiled mode" + }, + { + name: "TEXTURE_WRAP_CLAMP", + value: 1, + description: "Clamps texture to edge pixel in tiled mode" + }, + { + name: "TEXTURE_WRAP_MIRROR_REPEAT", + value: 2, + description: "Mirrors and repeats the texture in tiled mode" + }, + { + name: "TEXTURE_WRAP_MIRROR_CLAMP", + value: 3, + description: "Mirrors and clamps to border the texture in tiled mode" + } + ] + }, + { + name: "CubemapLayout", + description: "Cubemap layouts", + values: [ + { + name: "CUBEMAP_LAYOUT_AUTO_DETECT", + value: 0, + description: "Automatically detect layout type" + }, + { + name: "CUBEMAP_LAYOUT_LINE_VERTICAL", + value: 1, + description: "Layout is defined by a vertical line with faces" + }, + { + name: "CUBEMAP_LAYOUT_LINE_HORIZONTAL", + value: 2, + description: "Layout is defined by a horizontal line with faces" + }, + { + name: "CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR", + value: 3, + description: "Layout is defined by a 3x4 cross with cubemap faces" + }, + { + name: "CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE", + value: 4, + description: "Layout is defined by a 4x3 cross with cubemap faces" + } + ] + }, + { + name: "FontType", + description: "Font type, defines generation method", + values: [ + { + name: "FONT_DEFAULT", + value: 0, + description: "Default font generation, anti-aliased" + }, + { + name: "FONT_BITMAP", + value: 1, + description: "Bitmap font generation, no anti-aliasing" + }, + { + name: "FONT_SDF", + value: 2, + description: "SDF font generation, requires external shader" + } + ] + }, + { + name: "BlendMode", + description: "Color blending modes (pre-defined)", + values: [ + { + name: "BLEND_ALPHA", + value: 0, + description: "Blend textures considering alpha (default)" + }, + { + name: "BLEND_ADDITIVE", + value: 1, + description: "Blend textures adding colors" + }, + { + name: "BLEND_MULTIPLIED", + value: 2, + description: "Blend textures multiplying colors" + }, + { + name: "BLEND_ADD_COLORS", + value: 3, + description: "Blend textures adding colors (alternative)" + }, + { + name: "BLEND_SUBTRACT_COLORS", + value: 4, + description: "Blend textures subtracting colors (alternative)" + }, + { + name: "BLEND_ALPHA_PREMULTIPLY", + value: 5, + description: "Blend premultiplied textures considering alpha" + }, + { + name: "BLEND_CUSTOM", + value: 6, + description: "Blend textures using custom src/dst factors (use rlSetBlendFactors())" + }, + { + name: "BLEND_CUSTOM_SEPARATE", + value: 7, + description: "Blend textures using custom rgb/alpha separate src/dst factors (use rlSetBlendFactorsSeparate())" + } + ] + }, + { + name: "Gesture", + description: "Gesture", + values: [ + { + name: "GESTURE_NONE", + value: 0, + description: "No gesture" + }, + { + name: "GESTURE_TAP", + value: 1, + description: "Tap gesture" + }, + { + name: "GESTURE_DOUBLETAP", + value: 2, + description: "Double tap gesture" + }, + { + name: "GESTURE_HOLD", + value: 4, + description: "Hold gesture" + }, + { + name: "GESTURE_DRAG", + value: 8, + description: "Drag gesture" + }, + { + name: "GESTURE_SWIPE_RIGHT", + value: 16, + description: "Swipe right gesture" + }, + { + name: "GESTURE_SWIPE_LEFT", + value: 32, + description: "Swipe left gesture" + }, + { + name: "GESTURE_SWIPE_UP", + value: 64, + description: "Swipe up gesture" + }, + { + name: "GESTURE_SWIPE_DOWN", + value: 128, + description: "Swipe down gesture" + }, + { + name: "GESTURE_PINCH_IN", + value: 256, + description: "Pinch in gesture" + }, + { + name: "GESTURE_PINCH_OUT", + value: 512, + description: "Pinch out gesture" + } + ] + }, + { + name: "CameraMode", + description: "Camera system modes", + values: [ + { + name: "CAMERA_CUSTOM", + value: 0, + description: "Camera custom, controlled by user (UpdateCamera() does nothing)" + }, + { + name: "CAMERA_FREE", + value: 1, + description: "Camera free mode" + }, + { + name: "CAMERA_ORBITAL", + value: 2, + description: "Camera orbital, around target, zoom supported" + }, + { + name: "CAMERA_FIRST_PERSON", + value: 3, + description: "Camera first person" + }, + { + name: "CAMERA_THIRD_PERSON", + value: 4, + description: "Camera third person" + } + ] + }, + { + name: "CameraProjection", + description: "Camera projection", + values: [ + { + name: "CAMERA_PERSPECTIVE", + value: 0, + description: "Perspective projection" + }, + { + name: "CAMERA_ORTHOGRAPHIC", + value: 1, + description: "Orthographic projection" + } + ] + }, + { + name: "NPatchLayout", + description: "N-patch layout", + values: [ + { + name: "NPATCH_NINE_PATCH", + value: 0, + description: "Npatch layout: 3x3 tiles" + }, + { + name: "NPATCH_THREE_PATCH_VERTICAL", + value: 1, + description: "Npatch layout: 1x3 tiles" + }, + { + name: "NPATCH_THREE_PATCH_HORIZONTAL", + value: 2, + description: "Npatch layout: 3x1 tiles" + } + ] + } + ], + callbacks: [ + { + name: "TraceLogCallback", + description: "Logging: Redirect trace log messages", + returnType: "void", + params: [ + {type: "int", name: "logLevel"}, + {type: "const char *", name: "text"}, + {type: "va_list", name: "args"} + ] + }, + { + name: "LoadFileDataCallback", + description: "FileIO: Load binary data", + returnType: "unsigned char *", + params: [ + {type: "const char *", name: "fileName"}, + {type: "int *", name: "dataSize"} + ] + }, + { + name: "SaveFileDataCallback", + description: "FileIO: Save binary data", + returnType: "bool", + params: [ + {type: "const char *", name: "fileName"}, + {type: "const void *", name: "data"}, + {type: "int", name: "dataSize"} + ] + }, + { + name: "LoadFileTextCallback", + description: "FileIO: Load text data", + returnType: "char *", + params: [ + {type: "const char *", name: "fileName"} + ] + }, + { + name: "SaveFileTextCallback", + description: "FileIO: Save text data", + returnType: "bool", + params: [ + {type: "const char *", name: "fileName"}, + {type: "const char *", name: "text"} + ] + }, + { + name: "AudioCallback", + description: "", + returnType: "void", + params: [ + {type: "void *", name: "bufferData"}, + {type: "unsigned int", name: "frames"} + ] + } + ], + functions: [ + { + name: "InitWindow", + description: "Initialize window and OpenGL context", + returnType: "void", + params: [ + {type: "int", name: "width"}, + {type: "int", name: "height"}, + {type: "const char *", name: "title"} + ] + }, + { + name: "CloseWindow", + description: "Close window and unload OpenGL context", + returnType: "void" + }, + { + name: "WindowShouldClose", + description: "Check if application should close (KEY_ESCAPE pressed or windows close icon clicked)", + returnType: "bool" + }, + { + name: "IsWindowReady", + description: "Check if window has been initialized successfully", + returnType: "bool" + }, + { + name: "IsWindowFullscreen", + description: "Check if window is currently fullscreen", + returnType: "bool" + }, + { + name: "IsWindowHidden", + description: "Check if window is currently hidden", + returnType: "bool" + }, + { + name: "IsWindowMinimized", + description: "Check if window is currently minimized", + returnType: "bool" + }, + { + name: "IsWindowMaximized", + description: "Check if window is currently maximized", + returnType: "bool" + }, + { + name: "IsWindowFocused", + description: "Check if window is currently focused", + returnType: "bool" + }, + { + name: "IsWindowResized", + description: "Check if window has been resized last frame", + returnType: "bool" + }, + { + name: "IsWindowState", + description: "Check if one specific window flag is enabled", + returnType: "bool", + params: [ + {type: "unsigned int", name: "flag"} + ] + }, + { + name: "SetWindowState", + description: "Set window configuration state using flags", + returnType: "void", + params: [ + {type: "unsigned int", name: "flags"} + ] + }, + { + name: "ClearWindowState", + description: "Clear window configuration state flags", + returnType: "void", + params: [ + {type: "unsigned int", name: "flags"} + ] + }, + { + name: "ToggleFullscreen", + description: "Toggle window state: fullscreen/windowed, resizes monitor to match window resolution", + returnType: "void" + }, + { + name: "ToggleBorderlessWindowed", + description: "Toggle window state: borderless windowed, resizes window to match monitor resolution", + returnType: "void" + }, + { + name: "MaximizeWindow", + description: "Set window state: maximized, if resizable", + returnType: "void" + }, + { + name: "MinimizeWindow", + description: "Set window state: minimized, if resizable", + returnType: "void" + }, + { + name: "RestoreWindow", + description: "Restore window from being minimized/maximized", + returnType: "void" + }, + { + name: "SetWindowIcon", + description: "Set icon for window (single image, RGBA 32bit)", + returnType: "void", + params: [ + {type: "Image", name: "image"} + ] + }, + { + name: "SetWindowIcons", + description: "Set icon for window (multiple images, RGBA 32bit)", + returnType: "void", + params: [ + {type: "Image *", name: "images"}, + {type: "int", name: "count"} + ] + }, + { + name: "SetWindowTitle", + description: "Set title for window", + returnType: "void", + params: [ + {type: "const char *", name: "title"} + ] + }, + { + name: "SetWindowPosition", + description: "Set window position on screen", + returnType: "void", + params: [ + {type: "int", name: "x"}, + {type: "int", name: "y"} + ] + }, + { + name: "SetWindowMonitor", + description: "Set monitor for the current window", + returnType: "void", + params: [ + {type: "int", name: "monitor"} + ] + }, + { + name: "SetWindowMinSize", + description: "Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE)", + returnType: "void", + params: [ + {type: "int", name: "width"}, + {type: "int", name: "height"} + ] + }, + { + name: "SetWindowMaxSize", + description: "Set window maximum dimensions (for FLAG_WINDOW_RESIZABLE)", + returnType: "void", + params: [ + {type: "int", name: "width"}, + {type: "int", name: "height"} + ] + }, + { + name: "SetWindowSize", + description: "Set window dimensions", + returnType: "void", + params: [ + {type: "int", name: "width"}, + {type: "int", name: "height"} + ] + }, + { + name: "SetWindowOpacity", + description: "Set window opacity [0.0f..1.0f]", + returnType: "void", + params: [ + {type: "float", name: "opacity"} + ] + }, + { + name: "SetWindowFocused", + description: "Set window focused", + returnType: "void" + }, + { + name: "GetWindowHandle", + description: "Get native window handle", + returnType: "void *" + }, + { + name: "GetScreenWidth", + description: "Get current screen width", + returnType: "int" + }, + { + name: "GetScreenHeight", + description: "Get current screen height", + returnType: "int" + }, + { + name: "GetRenderWidth", + description: "Get current render width (it considers HiDPI)", + returnType: "int" + }, + { + name: "GetRenderHeight", + description: "Get current render height (it considers HiDPI)", + returnType: "int" + }, + { + name: "GetMonitorCount", + description: "Get number of connected monitors", + returnType: "int" + }, + { + name: "GetCurrentMonitor", + description: "Get current monitor where window is placed", + returnType: "int" + }, + { + name: "GetMonitorPosition", + description: "Get specified monitor position", + returnType: "Vector2", + params: [ + {type: "int", name: "monitor"} + ] + }, + { + name: "GetMonitorWidth", + description: "Get specified monitor width (current video mode used by monitor)", + returnType: "int", + params: [ + {type: "int", name: "monitor"} + ] + }, + { + name: "GetMonitorHeight", + description: "Get specified monitor height (current video mode used by monitor)", + returnType: "int", + params: [ + {type: "int", name: "monitor"} + ] + }, + { + name: "GetMonitorPhysicalWidth", + description: "Get specified monitor physical width in millimetres", + returnType: "int", + params: [ + {type: "int", name: "monitor"} + ] + }, + { + name: "GetMonitorPhysicalHeight", + description: "Get specified monitor physical height in millimetres", + returnType: "int", + params: [ + {type: "int", name: "monitor"} + ] + }, + { + name: "GetMonitorRefreshRate", + description: "Get specified monitor refresh rate", + returnType: "int", + params: [ + {type: "int", name: "monitor"} + ] + }, + { + name: "GetWindowPosition", + description: "Get window position XY on monitor", + returnType: "Vector2" + }, + { + name: "GetWindowScaleDPI", + description: "Get window scale DPI factor", + returnType: "Vector2" + }, + { + name: "GetMonitorName", + description: "Get the human-readable, UTF-8 encoded name of the specified monitor", + returnType: "const char *", + params: [ + {type: "int", name: "monitor"} + ] + }, + { + name: "SetClipboardText", + description: "Set clipboard text content", + returnType: "void", + params: [ + {type: "const char *", name: "text"} + ] + }, + { + name: "GetClipboardText", + description: "Get clipboard text content", + returnType: "const char *" + }, + { + name: "GetClipboardImage", + description: "Get clipboard image content", + returnType: "Image" + }, + { + name: "EnableEventWaiting", + description: "Enable waiting for events on EndDrawing(), no automatic event polling", + returnType: "void" + }, + { + name: "DisableEventWaiting", + description: "Disable waiting for events on EndDrawing(), automatic events polling", + returnType: "void" + }, + { + name: "ShowCursor", + description: "Show cursor", + returnType: "void" + }, + { + name: "HideCursor", + description: "Hide cursor", + returnType: "void" + }, + { + name: "IsCursorHidden", + description: "Check if cursor is not visible", + returnType: "bool" + }, + { + name: "EnableCursor", + description: "Enable cursor (unlock cursor)", + returnType: "void" + }, + { + name: "DisableCursor", + description: "Disable cursor (lock cursor)", + returnType: "void" + }, + { + name: "IsCursorOnScreen", + description: "Check if cursor is on the screen", + returnType: "bool" + }, + { + name: "ClearBackground", + description: "Clear background (framebuffer) to color", + returnType: "void", + params: [ + {type: "Color", name: "color"} + ] + }, + { + name: "BeginDrawing", + description: "Begin canvas (framebuffer) drawing", + returnType: "void" + }, + { + name: "EndDrawing", + description: "End canvas (framebuffer) drawing and swap buffers (double buffering)", + returnType: "void" + }, + { + name: "BeginMode2D", + description: "Begin 2D mode with custom camera (2D)", + returnType: "void", + params: [ + {type: "Camera2D", name: "camera"} + ] + }, + { + name: "EndMode2D", + description: "End 2D mode with custom camera", + returnType: "void" + }, + { + name: "BeginMode3D", + description: "Begin 3D mode with custom camera (3D)", + returnType: "void", + params: [ + {type: "Camera3D", name: "camera"} + ] + }, + { + name: "EndMode3D", + description: "End 3D mode and returns to default 2D orthographic mode", + returnType: "void" + }, + { + name: "BeginTextureMode", + description: "Begin drawing to render texture", + returnType: "void", + params: [ + {type: "RenderTexture2D", name: "target"} + ] + }, + { + name: "EndTextureMode", + description: "End drawing to render texture", + returnType: "void" + }, + { + name: "BeginShaderMode", + description: "Begin custom shader drawing", + returnType: "void", + params: [ + {type: "Shader", name: "shader"} + ] + }, + { + name: "EndShaderMode", + description: "End custom shader drawing (use default shader)", + returnType: "void" + }, + { + name: "BeginBlendMode", + description: "Begin blending mode (alpha, additive, multiplied, subtract, custom)", + returnType: "void", + params: [ + {type: "int", name: "mode"} + ] + }, + { + name: "EndBlendMode", + description: "End blending mode (reset to default: alpha blending)", + returnType: "void" + }, + { + name: "BeginScissorMode", + description: "Begin scissor mode (define screen area for following drawing)", + returnType: "void", + params: [ + {type: "int", name: "x"}, + {type: "int", name: "y"}, + {type: "int", name: "width"}, + {type: "int", name: "height"} + ] + }, + { + name: "EndScissorMode", + description: "End scissor mode", + returnType: "void" + }, + { + name: "BeginVrStereoMode", + description: "Begin stereo rendering (requires VR simulator)", + returnType: "void", + params: [ + {type: "VrStereoConfig", name: "config"} + ] + }, + { + name: "EndVrStereoMode", + description: "End stereo rendering (requires VR simulator)", + returnType: "void" + }, + { + name: "LoadVrStereoConfig", + description: "Load VR stereo config for VR simulator device parameters", + returnType: "VrStereoConfig", + params: [ + {type: "VrDeviceInfo", name: "device"} + ] + }, + { + name: "UnloadVrStereoConfig", + description: "Unload VR stereo config", + returnType: "void", + params: [ + {type: "VrStereoConfig", name: "config"} + ] + }, + { + name: "LoadShader", + description: "Load shader from files and bind default locations", + returnType: "Shader", + params: [ + {type: "const char *", name: "vsFileName"}, + {type: "const char *", name: "fsFileName"} + ] + }, + { + name: "LoadShaderFromMemory", + description: "Load shader from code strings and bind default locations", + returnType: "Shader", + params: [ + {type: "const char *", name: "vsCode"}, + {type: "const char *", name: "fsCode"} + ] + }, + { + name: "IsShaderValid", + description: "Check if shader is valid (loaded on GPU)", + returnType: "bool", + params: [ + {type: "Shader", name: "shader"} + ] + }, + { + name: "GetShaderLocation", + description: "Get shader uniform location", + returnType: "int", + params: [ + {type: "Shader", name: "shader"}, + {type: "const char *", name: "uniformName"} + ] + }, + { + name: "GetShaderLocationAttrib", + description: "Get shader attribute location", + returnType: "int", + params: [ + {type: "Shader", name: "shader"}, + {type: "const char *", name: "attribName"} + ] + }, + { + name: "SetShaderValue", + description: "Set shader uniform value", + returnType: "void", + params: [ + {type: "Shader", name: "shader"}, + {type: "int", name: "locIndex"}, + {type: "const void *", name: "value"}, + {type: "int", name: "uniformType"} + ] + }, + { + name: "SetShaderValueV", + description: "Set shader uniform value vector", + returnType: "void", + params: [ + {type: "Shader", name: "shader"}, + {type: "int", name: "locIndex"}, + {type: "const void *", name: "value"}, + {type: "int", name: "uniformType"}, + {type: "int", name: "count"} + ] + }, + { + name: "SetShaderValueMatrix", + description: "Set shader uniform value (matrix 4x4)", + returnType: "void", + params: [ + {type: "Shader", name: "shader"}, + {type: "int", name: "locIndex"}, + {type: "Matrix", name: "mat"} + ] + }, + { + name: "SetShaderValueTexture", + description: "Set shader uniform value and bind the texture (sampler2d)", + returnType: "void", + params: [ + {type: "Shader", name: "shader"}, + {type: "int", name: "locIndex"}, + {type: "Texture2D", name: "texture"} + ] + }, + { + name: "UnloadShader", + description: "Unload shader from GPU memory (VRAM)", + returnType: "void", + params: [ + {type: "Shader", name: "shader"} + ] + }, + { + name: "GetScreenToWorldRay", + description: "Get a ray trace from screen position (i.e mouse)", + returnType: "Ray", + params: [ + {type: "Vector2", name: "position"}, + {type: "Camera", name: "camera"} + ] + }, + { + name: "GetScreenToWorldRayEx", + description: "Get a ray trace from screen position (i.e mouse) in a viewport", + returnType: "Ray", + params: [ + {type: "Vector2", name: "position"}, + {type: "Camera", name: "camera"}, + {type: "int", name: "width"}, + {type: "int", name: "height"} + ] + }, + { + name: "GetWorldToScreen", + description: "Get screen space position for a 3d world space position", + returnType: "Vector2", + params: [ + {type: "Vector3", name: "position"}, + {type: "Camera", name: "camera"} + ] + }, + { + name: "GetWorldToScreenEx", + description: "Get sized screen space position for a 3d world space position", + returnType: "Vector2", + params: [ + {type: "Vector3", name: "position"}, + {type: "Camera", name: "camera"}, + {type: "int", name: "width"}, + {type: "int", name: "height"} + ] + }, + { + name: "GetWorldToScreen2D", + description: "Get screen space position for a 2d camera world space position", + returnType: "Vector2", + params: [ + {type: "Vector2", name: "position"}, + {type: "Camera2D", name: "camera"} + ] + }, + { + name: "GetScreenToWorld2D", + description: "Get world space position for a 2d camera screen space position", + returnType: "Vector2", + params: [ + {type: "Vector2", name: "position"}, + {type: "Camera2D", name: "camera"} + ] + }, + { + name: "GetCameraMatrix", + description: "Get camera transform matrix (view matrix)", + returnType: "Matrix", + params: [ + {type: "Camera", name: "camera"} + ] + }, + { + name: "GetCameraMatrix2D", + description: "Get camera 2d transform matrix", + returnType: "Matrix", + params: [ + {type: "Camera2D", name: "camera"} + ] + }, + { + name: "SetTargetFPS", + description: "Set target FPS (maximum)", + returnType: "void", + params: [ + {type: "int", name: "fps"} + ] + }, + { + name: "GetFrameTime", + description: "Get time in seconds for last frame drawn (delta time)", + returnType: "float" + }, + { + name: "GetTime", + description: "Get elapsed time in seconds since InitWindow()", + returnType: "double" + }, + { + name: "GetFPS", + description: "Get current FPS", + returnType: "int" + }, + { + name: "SwapScreenBuffer", + description: "Swap back buffer with front buffer (screen drawing)", + returnType: "void" + }, + { + name: "PollInputEvents", + description: "Register all input events", + returnType: "void" + }, + { + name: "WaitTime", + description: "Wait for some time (halt program execution)", + returnType: "void", + params: [ + {type: "double", name: "seconds"} + ] + }, + { + name: "SetRandomSeed", + description: "Set the seed for the random number generator", + returnType: "void", + params: [ + {type: "unsigned int", name: "seed"} + ] + }, + { + name: "GetRandomValue", + description: "Get a random value between min and max (both included)", + returnType: "int", + params: [ + {type: "int", name: "min"}, + {type: "int", name: "max"} + ] + }, + { + name: "LoadRandomSequence", + description: "Load random values sequence, no values repeated", + returnType: "int *", + params: [ + {type: "unsigned int", name: "count"}, + {type: "int", name: "min"}, + {type: "int", name: "max"} + ] + }, + { + name: "UnloadRandomSequence", + description: "Unload random values sequence", + returnType: "void", + params: [ + {type: "int *", name: "sequence"} + ] + }, + { + name: "TakeScreenshot", + description: "Takes a screenshot of current screen (filename extension defines format)", + returnType: "void", + params: [ + {type: "const char *", name: "fileName"} + ] + }, + { + name: "SetConfigFlags", + description: "Set up init configuration flags (view FLAGS)", + returnType: "void", + params: [ + {type: "unsigned int", name: "flags"} + ] + }, + { + name: "OpenURL", + description: "Open URL with default system browser (if available)", + returnType: "void", + params: [ + {type: "const char *", name: "url"} + ] + }, + { + name: "SetTraceLogLevel", + description: "Set the current threshold (minimum) log level", + returnType: "void", + params: [ + {type: "int", name: "logLevel"} + ] + }, + { + name: "TraceLog", + description: "Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...)", + returnType: "void", + params: [ + {type: "int", name: "logLevel"}, + {type: "const char *", name: "text"}, + {type: "...", name: "args"} + ] + }, + { + name: "SetTraceLogCallback", + description: "Set custom trace log", + returnType: "void", + params: [ + {type: "TraceLogCallback", name: "callback"} + ] + }, + { + name: "MemAlloc", + description: "Internal memory allocator", + returnType: "void *", + params: [ + {type: "unsigned int", name: "size"} + ] + }, + { + name: "MemRealloc", + description: "Internal memory reallocator", + returnType: "void *", + params: [ + {type: "void *", name: "ptr"}, + {type: "unsigned int", name: "size"} + ] + }, + { + name: "MemFree", + description: "Internal memory free", + returnType: "void", + params: [ + {type: "void *", name: "ptr"} + ] + }, + { + name: "LoadFileData", + description: "Load file data as byte array (read)", + returnType: "unsigned char *", + params: [ + {type: "const char *", name: "fileName"}, + {type: "int *", name: "dataSize"} + ] + }, + { + name: "UnloadFileData", + description: "Unload file data allocated by LoadFileData()", + returnType: "void", + params: [ + {type: "unsigned char *", name: "data"} + ] + }, + { + name: "SaveFileData", + description: "Save data to file from byte array (write), returns true on success", + returnType: "bool", + params: [ + {type: "const char *", name: "fileName"}, + {type: "const void *", name: "data"}, + {type: "int", name: "dataSize"} + ] + }, + { + name: "ExportDataAsCode", + description: "Export data to code (.h), returns true on success", + returnType: "bool", + params: [ + {type: "const unsigned char *", name: "data"}, + {type: "int", name: "dataSize"}, + {type: "const char *", name: "fileName"} + ] + }, + { + name: "LoadFileText", + description: "Load text data from file (read), returns a '\\0' terminated string", + returnType: "char *", + params: [ + {type: "const char *", name: "fileName"} + ] + }, + { + name: "UnloadFileText", + description: "Unload file text data allocated by LoadFileText()", + returnType: "void", + params: [ + {type: "char *", name: "text"} + ] + }, + { + name: "SaveFileText", + description: "Save text data to file (write), string must be '\\0' terminated, returns true on success", + returnType: "bool", + params: [ + {type: "const char *", name: "fileName"}, + {type: "const char *", name: "text"} + ] + }, + { + name: "SetLoadFileDataCallback", + description: "Set custom file binary data loader", + returnType: "void", + params: [ + {type: "LoadFileDataCallback", name: "callback"} + ] + }, + { + name: "SetSaveFileDataCallback", + description: "Set custom file binary data saver", + returnType: "void", + params: [ + {type: "SaveFileDataCallback", name: "callback"} + ] + }, + { + name: "SetLoadFileTextCallback", + description: "Set custom file text data loader", + returnType: "void", + params: [ + {type: "LoadFileTextCallback", name: "callback"} + ] + }, + { + name: "SetSaveFileTextCallback", + description: "Set custom file text data saver", + returnType: "void", + params: [ + {type: "SaveFileTextCallback", name: "callback"} + ] + }, + { + name: "FileRename", + description: "Rename file (if exists), returns 0 on success", + returnType: "int", + params: [ + {type: "const char *", name: "fileName"}, + {type: "const char *", name: "fileRename"} + ] + }, + { + name: "FileRemove", + description: "Remove file (if exists), returns 0 on success", + returnType: "int", + params: [ + {type: "const char *", name: "fileName"} + ] + }, + { + name: "FileCopy", + description: "Copy file from one path to another, dstPath created if it doesn't exist, returns 0 on success", + returnType: "int", + params: [ + {type: "const char *", name: "srcPath"}, + {type: "const char *", name: "dstPath"} + ] + }, + { + name: "FileMove", + description: "Move file from one directory to another, dstPath created if it doesn't exist, returns 0 on success", + returnType: "int", + params: [ + {type: "const char *", name: "srcPath"}, + {type: "const char *", name: "dstPath"} + ] + }, + { + name: "FileTextReplace", + description: "Replace text in an existing file, returns 0 on success", + returnType: "int", + params: [ + {type: "const char *", name: "fileName"}, + {type: "const char *", name: "search"}, + {type: "const char *", name: "replacement"} + ] + }, + { + name: "FileTextFindIndex", + description: "Find text in existing file, returns -1 if index not found or index otherwise", + returnType: "int", + params: [ + {type: "const char *", name: "fileName"}, + {type: "const char *", name: "search"} + ] + }, + { + name: "FileExists", + description: "Check if file exists", + returnType: "bool", + params: [ + {type: "const char *", name: "fileName"} + ] + }, + { + name: "DirectoryExists", + description: "Check if directory path exists", + returnType: "bool", + params: [ + {type: "const char *", name: "dirPath"} + ] + }, + { + name: "IsFileExtension", + description: "Check file extension (recommended include point: .png, .wav)", + returnType: "bool", + params: [ + {type: "const char *", name: "fileName"}, + {type: "const char *", name: "ext"} + ] + }, + { + name: "GetFileLength", + description: "Get file length in bytes (NOTE: GetFileSize() conflicts with windows.h)", + returnType: "int", + params: [ + {type: "const char *", name: "fileName"} + ] + }, + { + name: "GetFileModTime", + description: "Get file modification time (last write time)", + returnType: "long", + params: [ + {type: "const char *", name: "fileName"} + ] + }, + { + name: "GetFileExtension", + description: "Get pointer to extension for a filename string (includes dot: '.png')", + returnType: "const char *", + params: [ + {type: "const char *", name: "fileName"} + ] + }, + { + name: "GetFileName", + description: "Get pointer to filename for a path string", + returnType: "const char *", + params: [ + {type: "const char *", name: "filePath"} + ] + }, + { + name: "GetFileNameWithoutExt", + description: "Get filename string without extension (uses static string)", + returnType: "const char *", + params: [ + {type: "const char *", name: "filePath"} + ] + }, + { + name: "GetDirectoryPath", + description: "Get full path for a given fileName with path (uses static string)", + returnType: "const char *", + params: [ + {type: "const char *", name: "filePath"} + ] + }, + { + name: "GetPrevDirectoryPath", + description: "Get previous directory path for a given path (uses static string)", + returnType: "const char *", + params: [ + {type: "const char *", name: "dirPath"} + ] + }, + { + name: "GetWorkingDirectory", + description: "Get current working directory (uses static string)", + returnType: "const char *" + }, + { + name: "GetApplicationDirectory", + description: "Get the directory of the running application (uses static string)", + returnType: "const char *" + }, + { + name: "MakeDirectory", + description: "Create directories (including full path requested), returns 0 on success", + returnType: "int", + params: [ + {type: "const char *", name: "dirPath"} + ] + }, + { + name: "ChangeDirectory", + description: "Change working directory, returns 0 on success", + returnType: "int", + params: [ + {type: "const char *", name: "dirPath"} + ] + }, + { + name: "IsPathFile", + description: "Check if given path is a file or a directory", + returnType: "bool", + params: [ + {type: "const char *", name: "path"} + ] + }, + { + name: "IsFileNameValid", + description: "Check if fileName is valid for the platform/OS", + returnType: "bool", + params: [ + {type: "const char *", name: "fileName"} + ] + }, + { + name: "LoadDirectoryFiles", + description: "Load directory filepaths, files and directories, no subdirs scan", + returnType: "FilePathList", + params: [ + {type: "const char *", name: "dirPath"} + ] + }, + { + name: "LoadDirectoryFilesEx", + description: "Load directory filepaths with extension filtering and subdir scan; some filters available: '*.*','FILES*','DIRS*'", + returnType: "FilePathList", + params: [ + {type: "const char *", name: "basePath"}, + {type: "const char *", name: "filter"}, + {type: "bool", name: "scanSubdirs"} + ] + }, + { + name: "UnloadDirectoryFiles", + description: "Unload filepaths", + returnType: "void", + params: [ + {type: "FilePathList", name: "files"} + ] + }, + { + name: "IsFileDropped", + description: "Check if file has been dropped into window", + returnType: "bool" + }, + { + name: "LoadDroppedFiles", + description: "Load dropped filepaths", + returnType: "FilePathList" + }, + { + name: "UnloadDroppedFiles", + description: "Unload dropped filepaths", + returnType: "void", + params: [ + {type: "FilePathList", name: "files"} + ] + }, + { + name: "GetDirectoryFileCount", + description: "Get the file count in a directory", + returnType: "unsigned int", + params: [ + {type: "const char *", name: "dirPath"} + ] + }, + { + name: "GetDirectoryFileCountEx", + description: "Get the file count in a directory with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result", + returnType: "unsigned int", + params: [ + {type: "const char *", name: "basePath"}, + {type: "const char *", name: "filter"}, + {type: "bool", name: "scanSubdirs"} + ] + }, + { + name: "CompressData", + description: "Compress data (DEFLATE algorithm), memory must be MemFree()", + returnType: "unsigned char *", + params: [ + {type: "const unsigned char *", name: "data"}, + {type: "int", name: "dataSize"}, + {type: "int *", name: "compDataSize"} + ] + }, + { + name: "DecompressData", + description: "Decompress data (DEFLATE algorithm), memory must be MemFree()", + returnType: "unsigned char *", + params: [ + {type: "const unsigned char *", name: "compData"}, + {type: "int", name: "compDataSize"}, + {type: "int *", name: "dataSize"} + ] + }, + { + name: "EncodeDataBase64", + description: "Encode data to Base64 string (includes NULL terminator), memory must be MemFree()", + returnType: "char *", + params: [ + {type: "const unsigned char *", name: "data"}, + {type: "int", name: "dataSize"}, + {type: "int *", name: "outputSize"} + ] + }, + { + name: "DecodeDataBase64", + description: "Decode Base64 string (expected NULL terminated), memory must be MemFree()", + returnType: "unsigned char *", + params: [ + {type: "const char *", name: "text"}, + {type: "int *", name: "outputSize"} + ] + }, + { + name: "ComputeCRC32", + description: "Compute CRC32 hash code", + returnType: "unsigned int", + params: [ + {type: "const unsigned char *", name: "data"}, + {type: "int", name: "dataSize"} + ] + }, + { + name: "ComputeMD5", + description: "Compute MD5 hash code, returns static int[4] (16 bytes)", + returnType: "unsigned int *", + params: [ + {type: "const unsigned char *", name: "data"}, + {type: "int", name: "dataSize"} + ] + }, + { + name: "ComputeSHA1", + description: "Compute SHA1 hash code, returns static int[5] (20 bytes)", + returnType: "unsigned int *", + params: [ + {type: "const unsigned char *", name: "data"}, + {type: "int", name: "dataSize"} + ] + }, + { + name: "ComputeSHA256", + description: "Compute SHA256 hash code, returns static int[8] (32 bytes)", + returnType: "unsigned int *", + params: [ + {type: "const unsigned char *", name: "data"}, + {type: "int", name: "dataSize"} + ] + }, + { + name: "LoadAutomationEventList", + description: "Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS", + returnType: "AutomationEventList", + params: [ + {type: "const char *", name: "fileName"} + ] + }, + { + name: "UnloadAutomationEventList", + description: "Unload automation events list from file", + returnType: "void", + params: [ + {type: "AutomationEventList", name: "list"} + ] + }, + { + name: "ExportAutomationEventList", + description: "Export automation events list as text file", + returnType: "bool", + params: [ + {type: "AutomationEventList", name: "list"}, + {type: "const char *", name: "fileName"} + ] + }, + { + name: "SetAutomationEventList", + description: "Set automation event list to record to", + returnType: "void", + params: [ + {type: "AutomationEventList *", name: "list"} + ] + }, + { + name: "SetAutomationEventBaseFrame", + description: "Set automation event internal base frame to start recording", + returnType: "void", + params: [ + {type: "int", name: "frame"} + ] + }, + { + name: "StartAutomationEventRecording", + description: "Start recording automation events (AutomationEventList must be set)", + returnType: "void" + }, + { + name: "StopAutomationEventRecording", + description: "Stop recording automation events", + returnType: "void" + }, + { + name: "PlayAutomationEvent", + description: "Play a recorded automation event", + returnType: "void", + params: [ + {type: "AutomationEvent", name: "event"} + ] + }, + { + name: "IsKeyPressed", + description: "Check if key has been pressed once", + returnType: "bool", + params: [ + {type: "int", name: "key"} + ] + }, + { + name: "IsKeyPressedRepeat", + description: "Check if key has been pressed again", + returnType: "bool", + params: [ + {type: "int", name: "key"} + ] + }, + { + name: "IsKeyDown", + description: "Check if key is being pressed", + returnType: "bool", + params: [ + {type: "int", name: "key"} + ] + }, + { + name: "IsKeyReleased", + description: "Check if key has been released once", + returnType: "bool", + params: [ + {type: "int", name: "key"} + ] + }, + { + name: "IsKeyUp", + description: "Check if key is NOT being pressed", + returnType: "bool", + params: [ + {type: "int", name: "key"} + ] + }, + { + name: "GetKeyPressed", + description: "Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty", + returnType: "int" + }, + { + name: "GetCharPressed", + description: "Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty", + returnType: "int" + }, + { + name: "GetKeyName", + description: "Get name of a QWERTY key on the current keyboard layout (eg returns string 'q' for KEY_A on an AZERTY keyboard)", + returnType: "const char *", + params: [ + {type: "int", name: "key"} + ] + }, + { + name: "SetExitKey", + description: "Set a custom key to exit program (default is ESC)", + returnType: "void", + params: [ + {type: "int", name: "key"} + ] + }, + { + name: "IsGamepadAvailable", + description: "Check if gamepad is available", + returnType: "bool", + params: [ + {type: "int", name: "gamepad"} + ] + }, + { + name: "GetGamepadName", + description: "Get gamepad internal name id", + returnType: "const char *", + params: [ + {type: "int", name: "gamepad"} + ] + }, + { + name: "IsGamepadButtonPressed", + description: "Check if gamepad button has been pressed once", + returnType: "bool", + params: [ + {type: "int", name: "gamepad"}, + {type: "int", name: "button"} + ] + }, + { + name: "IsGamepadButtonDown", + description: "Check if gamepad button is being pressed", + returnType: "bool", + params: [ + {type: "int", name: "gamepad"}, + {type: "int", name: "button"} + ] + }, + { + name: "IsGamepadButtonReleased", + description: "Check if gamepad button has been released once", + returnType: "bool", + params: [ + {type: "int", name: "gamepad"}, + {type: "int", name: "button"} + ] + }, + { + name: "IsGamepadButtonUp", + description: "Check if gamepad button is NOT being pressed", + returnType: "bool", + params: [ + {type: "int", name: "gamepad"}, + {type: "int", name: "button"} + ] + }, + { + name: "GetGamepadButtonPressed", + description: "Get the last gamepad button pressed", + returnType: "int" + }, + { + name: "GetGamepadAxisCount", + description: "Get axis count for a gamepad", + returnType: "int", + params: [ + {type: "int", name: "gamepad"} + ] + }, + { + name: "GetGamepadAxisMovement", + description: "Get movement value for a gamepad axis", + returnType: "float", + params: [ + {type: "int", name: "gamepad"}, + {type: "int", name: "axis"} + ] + }, + { + name: "SetGamepadMappings", + description: "Set internal gamepad mappings (SDL_GameControllerDB)", + returnType: "int", + params: [ + {type: "const char *", name: "mappings"} + ] + }, + { + name: "SetGamepadVibration", + description: "Set gamepad vibration for both motors (duration in seconds)", + returnType: "void", + params: [ + {type: "int", name: "gamepad"}, + {type: "float", name: "leftMotor"}, + {type: "float", name: "rightMotor"}, + {type: "float", name: "duration"} + ] + }, + { + name: "IsMouseButtonPressed", + description: "Check if mouse button has been pressed once", + returnType: "bool", + params: [ + {type: "int", name: "button"} + ] + }, + { + name: "IsMouseButtonDown", + description: "Check if mouse button is being pressed", + returnType: "bool", + params: [ + {type: "int", name: "button"} + ] + }, + { + name: "IsMouseButtonReleased", + description: "Check if mouse button has been released once", + returnType: "bool", + params: [ + {type: "int", name: "button"} + ] + }, + { + name: "IsMouseButtonUp", + description: "Check if mouse button is NOT being pressed", + returnType: "bool", + params: [ + {type: "int", name: "button"} + ] + }, + { + name: "GetMouseX", + description: "Get mouse position X", + returnType: "int" + }, + { + name: "GetMouseY", + description: "Get mouse position Y", + returnType: "int" + }, + { + name: "GetMousePosition", + description: "Get mouse position XY", + returnType: "Vector2" + }, + { + name: "GetMouseDelta", + description: "Get mouse delta between frames", + returnType: "Vector2" + }, + { + name: "SetMousePosition", + description: "Set mouse position XY", + returnType: "void", + params: [ + {type: "int", name: "x"}, + {type: "int", name: "y"} + ] + }, + { + name: "SetMouseOffset", + description: "Set mouse offset", + returnType: "void", + params: [ + {type: "int", name: "offsetX"}, + {type: "int", name: "offsetY"} + ] + }, + { + name: "SetMouseScale", + description: "Set mouse scaling", + returnType: "void", + params: [ + {type: "float", name: "scaleX"}, + {type: "float", name: "scaleY"} + ] + }, + { + name: "GetMouseWheelMove", + description: "Get mouse wheel movement for X or Y, whichever is larger", + returnType: "float" + }, + { + name: "GetMouseWheelMoveV", + description: "Get mouse wheel movement for both X and Y", + returnType: "Vector2" + }, + { + name: "SetMouseCursor", + description: "Set mouse cursor", + returnType: "void", + params: [ + {type: "int", name: "cursor"} + ] + }, + { + name: "GetTouchX", + description: "Get touch position X for touch point 0 (relative to screen size)", + returnType: "int" + }, + { + name: "GetTouchY", + description: "Get touch position Y for touch point 0 (relative to screen size)", + returnType: "int" + }, + { + name: "GetTouchPosition", + description: "Get touch position XY for a touch point index (relative to screen size)", + returnType: "Vector2", + params: [ + {type: "int", name: "index"} + ] + }, + { + name: "GetTouchPointId", + description: "Get touch point identifier for given index", + returnType: "int", + params: [ + {type: "int", name: "index"} + ] + }, + { + name: "GetTouchPointCount", + description: "Get number of touch points", + returnType: "int" + }, + { + name: "SetGesturesEnabled", + description: "Enable a set of gestures using flags", + returnType: "void", + params: [ + {type: "unsigned int", name: "flags"} + ] + }, + { + name: "IsGestureDetected", + description: "Check if gesture has been detected", + returnType: "bool", + params: [ + {type: "unsigned int", name: "gesture"} + ] + }, + { + name: "GetGestureDetected", + description: "Get latest detected gesture", + returnType: "int" + }, + { + name: "GetGestureHoldDuration", + description: "Get gesture hold time in seconds", + returnType: "float" + }, + { + name: "GetGestureDragVector", + description: "Get gesture drag vector", + returnType: "Vector2" + }, + { + name: "GetGestureDragAngle", + description: "Get gesture drag angle", + returnType: "float" + }, + { + name: "GetGesturePinchVector", + description: "Get gesture pinch delta", + returnType: "Vector2" + }, + { + name: "GetGesturePinchAngle", + description: "Get gesture pinch angle", + returnType: "float" + }, + { + name: "UpdateCamera", + description: "Update camera position for selected mode", + returnType: "void", + params: [ + {type: "Camera *", name: "camera"}, + {type: "int", name: "mode"} + ] + }, + { + name: "UpdateCameraPro", + description: "Update camera movement/rotation", + returnType: "void", + params: [ + {type: "Camera *", name: "camera"}, + {type: "Vector3", name: "movement"}, + {type: "Vector3", name: "rotation"}, + {type: "float", name: "zoom"} + ] + }, + { + name: "SetShapesTexture", + description: "Set texture and rectangle to be used on shapes drawing", + returnType: "void", + params: [ + {type: "Texture2D", name: "texture"}, + {type: "Rectangle", name: "rec"} + ] + }, + { + name: "GetShapesTexture", + description: "Get texture that is used for shapes drawing", + returnType: "Texture2D" + }, + { + name: "GetShapesTextureRectangle", + description: "Get texture source rectangle that is used for shapes drawing", + returnType: "Rectangle" + }, + { + name: "DrawPixel", + description: "Draw a pixel using geometry [Can be slow, use with care]", + returnType: "void", + params: [ + {type: "int", name: "posX"}, + {type: "int", name: "posY"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawPixelV", + description: "Draw a pixel using geometry (Vector version) [Can be slow, use with care]", + returnType: "void", + params: [ + {type: "Vector2", name: "position"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawLine", + description: "Draw a line", + returnType: "void", + params: [ + {type: "int", name: "startPosX"}, + {type: "int", name: "startPosY"}, + {type: "int", name: "endPosX"}, + {type: "int", name: "endPosY"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawLineV", + description: "Draw a line (using gl lines)", + returnType: "void", + params: [ + {type: "Vector2", name: "startPos"}, + {type: "Vector2", name: "endPos"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawLineEx", + description: "Draw a line (using triangles/quads)", + returnType: "void", + params: [ + {type: "Vector2", name: "startPos"}, + {type: "Vector2", name: "endPos"}, + {type: "float", name: "thick"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawLineStrip", + description: "Draw lines sequence (using gl lines)", + returnType: "void", + params: [ + {type: "const Vector2 *", name: "points"}, + {type: "int", name: "pointCount"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawLineBezier", + description: "Draw line segment cubic-bezier in-out interpolation", + returnType: "void", + params: [ + {type: "Vector2", name: "startPos"}, + {type: "Vector2", name: "endPos"}, + {type: "float", name: "thick"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawLineDashed", + description: "Draw a dashed line", + returnType: "void", + params: [ + {type: "Vector2", name: "startPos"}, + {type: "Vector2", name: "endPos"}, + {type: "int", name: "dashSize"}, + {type: "int", name: "spaceSize"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawCircle", + description: "Draw a color-filled circle", + returnType: "void", + params: [ + {type: "int", name: "centerX"}, + {type: "int", name: "centerY"}, + {type: "float", name: "radius"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawCircleV", + description: "Draw a color-filled circle (Vector version)", + returnType: "void", + params: [ + {type: "Vector2", name: "center"}, + {type: "float", name: "radius"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawCircleGradient", + description: "Draw a gradient-filled circle", + returnType: "void", + params: [ + {type: "Vector2", name: "center"}, + {type: "float", name: "radius"}, + {type: "Color", name: "inner"}, + {type: "Color", name: "outer"} + ] + }, + { + name: "DrawCircleSector", + description: "Draw a piece of a circle", + returnType: "void", + params: [ + {type: "Vector2", name: "center"}, + {type: "float", name: "radius"}, + {type: "float", name: "startAngle"}, + {type: "float", name: "endAngle"}, + {type: "int", name: "segments"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawCircleSectorLines", + description: "Draw circle sector outline", + returnType: "void", + params: [ + {type: "Vector2", name: "center"}, + {type: "float", name: "radius"}, + {type: "float", name: "startAngle"}, + {type: "float", name: "endAngle"}, + {type: "int", name: "segments"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawCircleLines", + description: "Draw circle outline", + returnType: "void", + params: [ + {type: "int", name: "centerX"}, + {type: "int", name: "centerY"}, + {type: "float", name: "radius"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawCircleLinesV", + description: "Draw circle outline (Vector version)", + returnType: "void", + params: [ + {type: "Vector2", name: "center"}, + {type: "float", name: "radius"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawEllipse", + description: "Draw ellipse", + returnType: "void", + params: [ + {type: "int", name: "centerX"}, + {type: "int", name: "centerY"}, + {type: "float", name: "radiusH"}, + {type: "float", name: "radiusV"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawEllipseV", + description: "Draw ellipse (Vector version)", + returnType: "void", + params: [ + {type: "Vector2", name: "center"}, + {type: "float", name: "radiusH"}, + {type: "float", name: "radiusV"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawEllipseLines", + description: "Draw ellipse outline", + returnType: "void", + params: [ + {type: "int", name: "centerX"}, + {type: "int", name: "centerY"}, + {type: "float", name: "radiusH"}, + {type: "float", name: "radiusV"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawEllipseLinesV", + description: "Draw ellipse outline (Vector version)", + returnType: "void", + params: [ + {type: "Vector2", name: "center"}, + {type: "float", name: "radiusH"}, + {type: "float", name: "radiusV"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawRing", + description: "Draw ring", + returnType: "void", + params: [ + {type: "Vector2", name: "center"}, + {type: "float", name: "innerRadius"}, + {type: "float", name: "outerRadius"}, + {type: "float", name: "startAngle"}, + {type: "float", name: "endAngle"}, + {type: "int", name: "segments"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawRingLines", + description: "Draw ring outline", + returnType: "void", + params: [ + {type: "Vector2", name: "center"}, + {type: "float", name: "innerRadius"}, + {type: "float", name: "outerRadius"}, + {type: "float", name: "startAngle"}, + {type: "float", name: "endAngle"}, + {type: "int", name: "segments"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawRectangle", + description: "Draw a color-filled rectangle", + returnType: "void", + params: [ + {type: "int", name: "posX"}, + {type: "int", name: "posY"}, + {type: "int", name: "width"}, + {type: "int", name: "height"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawRectangleV", + description: "Draw a color-filled rectangle (Vector version)", + returnType: "void", + params: [ + {type: "Vector2", name: "position"}, + {type: "Vector2", name: "size"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawRectangleRec", + description: "Draw a color-filled rectangle", + returnType: "void", + params: [ + {type: "Rectangle", name: "rec"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawRectanglePro", + description: "Draw a color-filled rectangle with pro parameters", + returnType: "void", + params: [ + {type: "Rectangle", name: "rec"}, + {type: "Vector2", name: "origin"}, + {type: "float", name: "rotation"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawRectangleGradientV", + description: "Draw a vertical-gradient-filled rectangle", + returnType: "void", + params: [ + {type: "int", name: "posX"}, + {type: "int", name: "posY"}, + {type: "int", name: "width"}, + {type: "int", name: "height"}, + {type: "Color", name: "top"}, + {type: "Color", name: "bottom"} + ] + }, + { + name: "DrawRectangleGradientH", + description: "Draw a horizontal-gradient-filled rectangle", + returnType: "void", + params: [ + {type: "int", name: "posX"}, + {type: "int", name: "posY"}, + {type: "int", name: "width"}, + {type: "int", name: "height"}, + {type: "Color", name: "left"}, + {type: "Color", name: "right"} + ] + }, + { + name: "DrawRectangleGradientEx", + description: "Draw a gradient-filled rectangle with custom vertex colors", + returnType: "void", + params: [ + {type: "Rectangle", name: "rec"}, + {type: "Color", name: "topLeft"}, + {type: "Color", name: "bottomLeft"}, + {type: "Color", name: "bottomRight"}, + {type: "Color", name: "topRight"} + ] + }, + { + name: "DrawRectangleLines", + description: "Draw rectangle outline", + returnType: "void", + params: [ + {type: "int", name: "posX"}, + {type: "int", name: "posY"}, + {type: "int", name: "width"}, + {type: "int", name: "height"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawRectangleLinesEx", + description: "Draw rectangle outline with extended parameters", + returnType: "void", + params: [ + {type: "Rectangle", name: "rec"}, + {type: "float", name: "lineThick"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawRectangleRounded", + description: "Draw rectangle with rounded edges", + returnType: "void", + params: [ + {type: "Rectangle", name: "rec"}, + {type: "float", name: "roundness"}, + {type: "int", name: "segments"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawRectangleRoundedLines", + description: "Draw rectangle lines with rounded edges", + returnType: "void", + params: [ + {type: "Rectangle", name: "rec"}, + {type: "float", name: "roundness"}, + {type: "int", name: "segments"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawRectangleRoundedLinesEx", + description: "Draw rectangle lines with rounded edges outline", + returnType: "void", + params: [ + {type: "Rectangle", name: "rec"}, + {type: "float", name: "roundness"}, + {type: "int", name: "segments"}, + {type: "float", name: "lineThick"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawTriangle", + description: "Draw a color-filled triangle (vertex in counter-clockwise order!)", + returnType: "void", + params: [ + {type: "Vector2", name: "v1"}, + {type: "Vector2", name: "v2"}, + {type: "Vector2", name: "v3"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawTriangleGradient", + description: "Draw triangle with interpolated colors (vertex in counter-clockwise order!)", + returnType: "void", + params: [ + {type: "Vector2", name: "v1"}, + {type: "Vector2", name: "v2"}, + {type: "Vector2", name: "v3"}, + {type: "Color", name: "c1"}, + {type: "Color", name: "c2"}, + {type: "Color", name: "c3"} + ] + }, + { + name: "DrawTriangleLines", + description: "Draw triangle outline (vertex in counter-clockwise order!)", + returnType: "void", + params: [ + {type: "Vector2", name: "v1"}, + {type: "Vector2", name: "v2"}, + {type: "Vector2", name: "v3"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawTriangleFan", + description: "Draw a triangle fan defined by points (first vertex is the center)", + returnType: "void", + params: [ + {type: "const Vector2 *", name: "points"}, + {type: "int", name: "pointCount"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawTriangleStrip", + description: "Draw a triangle strip defined by points", + returnType: "void", + params: [ + {type: "const Vector2 *", name: "points"}, + {type: "int", name: "pointCount"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawPoly", + description: "Draw a polygon of n sides", + returnType: "void", + params: [ + {type: "Vector2", name: "center"}, + {type: "int", name: "sides"}, + {type: "float", name: "radius"}, + {type: "float", name: "rotation"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawPolyLines", + description: "Draw a polygon outline of n sides", + returnType: "void", + params: [ + {type: "Vector2", name: "center"}, + {type: "int", name: "sides"}, + {type: "float", name: "radius"}, + {type: "float", name: "rotation"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawPolyLinesEx", + description: "Draw a polygon outline of n sides with extended parameters", + returnType: "void", + params: [ + {type: "Vector2", name: "center"}, + {type: "int", name: "sides"}, + {type: "float", name: "radius"}, + {type: "float", name: "rotation"}, + {type: "float", name: "lineThick"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawSplineLinear", + description: "Draw spline: Linear, minimum 2 points", + returnType: "void", + params: [ + {type: "const Vector2 *", name: "points"}, + {type: "int", name: "pointCount"}, + {type: "float", name: "thick"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawSplineBasis", + description: "Draw spline: B-Spline, minimum 4 points", + returnType: "void", + params: [ + {type: "const Vector2 *", name: "points"}, + {type: "int", name: "pointCount"}, + {type: "float", name: "thick"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawSplineCatmullRom", + description: "Draw spline: Catmull-Rom, minimum 4 points", + returnType: "void", + params: [ + {type: "const Vector2 *", name: "points"}, + {type: "int", name: "pointCount"}, + {type: "float", name: "thick"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawSplineBezierQuadratic", + description: "Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...]", + returnType: "void", + params: [ + {type: "const Vector2 *", name: "points"}, + {type: "int", name: "pointCount"}, + {type: "float", name: "thick"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawSplineBezierCubic", + description: "Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...]", + returnType: "void", + params: [ + {type: "const Vector2 *", name: "points"}, + {type: "int", name: "pointCount"}, + {type: "float", name: "thick"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawSplineSegmentLinear", + description: "Draw spline segment: Linear, 2 points", + returnType: "void", + params: [ + {type: "Vector2", name: "p1"}, + {type: "Vector2", name: "p2"}, + {type: "float", name: "thick"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawSplineSegmentBasis", + description: "Draw spline segment: B-Spline, 4 points", + returnType: "void", + params: [ + {type: "Vector2", name: "p1"}, + {type: "Vector2", name: "p2"}, + {type: "Vector2", name: "p3"}, + {type: "Vector2", name: "p4"}, + {type: "float", name: "thick"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawSplineSegmentCatmullRom", + description: "Draw spline segment: Catmull-Rom, 4 points", + returnType: "void", + params: [ + {type: "Vector2", name: "p1"}, + {type: "Vector2", name: "p2"}, + {type: "Vector2", name: "p3"}, + {type: "Vector2", name: "p4"}, + {type: "float", name: "thick"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawSplineSegmentBezierQuadratic", + description: "Draw spline segment: Quadratic Bezier, 2 points, 1 control point", + returnType: "void", + params: [ + {type: "Vector2", name: "p1"}, + {type: "Vector2", name: "c2"}, + {type: "Vector2", name: "p3"}, + {type: "float", name: "thick"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawSplineSegmentBezierCubic", + description: "Draw spline segment: Cubic Bezier, 2 points, 2 control points", + returnType: "void", + params: [ + {type: "Vector2", name: "p1"}, + {type: "Vector2", name: "c2"}, + {type: "Vector2", name: "c3"}, + {type: "Vector2", name: "p4"}, + {type: "float", name: "thick"}, + {type: "Color", name: "color"} + ] + }, + { + name: "GetSplinePointLinear", + description: "Get (evaluate) spline point: Linear", + returnType: "Vector2", + params: [ + {type: "Vector2", name: "startPos"}, + {type: "Vector2", name: "endPos"}, + {type: "float", name: "t"} + ] + }, + { + name: "GetSplinePointBasis", + description: "Get (evaluate) spline point: B-Spline", + returnType: "Vector2", + params: [ + {type: "Vector2", name: "p1"}, + {type: "Vector2", name: "p2"}, + {type: "Vector2", name: "p3"}, + {type: "Vector2", name: "p4"}, + {type: "float", name: "t"} + ] + }, + { + name: "GetSplinePointCatmullRom", + description: "Get (evaluate) spline point: Catmull-Rom", + returnType: "Vector2", + params: [ + {type: "Vector2", name: "p1"}, + {type: "Vector2", name: "p2"}, + {type: "Vector2", name: "p3"}, + {type: "Vector2", name: "p4"}, + {type: "float", name: "t"} + ] + }, + { + name: "GetSplinePointBezierQuadratic", + description: "Get (evaluate) spline point: Quadratic Bezier", + returnType: "Vector2", + params: [ + {type: "Vector2", name: "p1"}, + {type: "Vector2", name: "c2"}, + {type: "Vector2", name: "p3"}, + {type: "float", name: "t"} + ] + }, + { + name: "GetSplinePointBezierCubic", + description: "Get (evaluate) spline point: Cubic Bezier", + returnType: "Vector2", + params: [ + {type: "Vector2", name: "p1"}, + {type: "Vector2", name: "c2"}, + {type: "Vector2", name: "c3"}, + {type: "Vector2", name: "p4"}, + {type: "float", name: "t"} + ] + }, + { + name: "CheckCollisionRecs", + description: "Check collision between two rectangles", + returnType: "bool", + params: [ + {type: "Rectangle", name: "rec1"}, + {type: "Rectangle", name: "rec2"} + ] + }, + { + name: "CheckCollisionCircles", + description: "Check collision between two circles", + returnType: "bool", + params: [ + {type: "Vector2", name: "center1"}, + {type: "float", name: "radius1"}, + {type: "Vector2", name: "center2"}, + {type: "float", name: "radius2"} + ] + }, + { + name: "CheckCollisionCircleRec", + description: "Check collision between circle and rectangle", + returnType: "bool", + params: [ + {type: "Vector2", name: "center"}, + {type: "float", name: "radius"}, + {type: "Rectangle", name: "rec"} + ] + }, + { + name: "CheckCollisionCircleLine", + description: "Check if circle collides with a line created between two points [p1] and [p2]", + returnType: "bool", + params: [ + {type: "Vector2", name: "center"}, + {type: "float", name: "radius"}, + {type: "Vector2", name: "p1"}, + {type: "Vector2", name: "p2"} + ] + }, + { + name: "CheckCollisionPointRec", + description: "Check if point is inside rectangle", + returnType: "bool", + params: [ + {type: "Vector2", name: "point"}, + {type: "Rectangle", name: "rec"} + ] + }, + { + name: "CheckCollisionPointCircle", + description: "Check if point is inside circle", + returnType: "bool", + params: [ + {type: "Vector2", name: "point"}, + {type: "Vector2", name: "center"}, + {type: "float", name: "radius"} + ] + }, + { + name: "CheckCollisionPointTriangle", + description: "Check if point is inside a triangle", + returnType: "bool", + params: [ + {type: "Vector2", name: "point"}, + {type: "Vector2", name: "p1"}, + {type: "Vector2", name: "p2"}, + {type: "Vector2", name: "p3"} + ] + }, + { + name: "CheckCollisionPointLine", + description: "Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold]", + returnType: "bool", + params: [ + {type: "Vector2", name: "point"}, + {type: "Vector2", name: "p1"}, + {type: "Vector2", name: "p2"}, + {type: "int", name: "threshold"} + ] + }, + { + name: "CheckCollisionPointPoly", + description: "Check if point is within a polygon described by array of vertices", + returnType: "bool", + params: [ + {type: "Vector2", name: "point"}, + {type: "const Vector2 *", name: "points"}, + {type: "int", name: "pointCount"} + ] + }, + { + name: "CheckCollisionLines", + description: "Check the collision between two lines defined by two points each, returns collision point by reference", + returnType: "bool", + params: [ + {type: "Vector2", name: "startPos1"}, + {type: "Vector2", name: "endPos1"}, + {type: "Vector2", name: "startPos2"}, + {type: "Vector2", name: "endPos2"}, + {type: "Vector2 *", name: "collisionPoint"} + ] + }, + { + name: "GetCollisionRec", + description: "Get collision rectangle for two rectangles collision", + returnType: "Rectangle", + params: [ + {type: "Rectangle", name: "rec1"}, + {type: "Rectangle", name: "rec2"} + ] + }, + { + name: "LoadImage", + description: "Load image from file into CPU memory (RAM)", + returnType: "Image", + params: [ + {type: "const char *", name: "fileName"} + ] + }, + { + name: "LoadImageRaw", + description: "Load image from RAW file data", + returnType: "Image", + params: [ + {type: "const char *", name: "fileName"}, + {type: "int", name: "width"}, + {type: "int", name: "height"}, + {type: "int", name: "format"}, + {type: "int", name: "headerSize"} + ] + }, + { + name: "LoadImageAnim", + description: "Load image sequence from file (frames appended to image.data)", + returnType: "Image", + params: [ + {type: "const char *", name: "fileName"}, + {type: "int *", name: "frames"} + ] + }, + { + name: "LoadImageAnimFromMemory", + description: "Load image sequence from memory buffer", + returnType: "Image", + params: [ + {type: "const char *", name: "fileType"}, + {type: "const unsigned char *", name: "fileData"}, + {type: "int", name: "dataSize"}, + {type: "int *", name: "frames"} + ] + }, + { + name: "LoadImageFromMemory", + description: "Load image from memory buffer, fileType refers to extension: i.e. '.png'", + returnType: "Image", + params: [ + {type: "const char *", name: "fileType"}, + {type: "const unsigned char *", name: "fileData"}, + {type: "int", name: "dataSize"} + ] + }, + { + name: "LoadImageFromTexture", + description: "Load image from GPU texture data", + returnType: "Image", + params: [ + {type: "Texture2D", name: "texture"} + ] + }, + { + name: "LoadImageFromScreen", + description: "Load image from screen buffer (screenshot)", + returnType: "Image" + }, + { + name: "IsImageValid", + description: "Check if an image is valid (data and parameters)", + returnType: "bool", + params: [ + {type: "Image", name: "image"} + ] + }, + { + name: "UnloadImage", + description: "Unload image from CPU memory (RAM)", + returnType: "void", + params: [ + {type: "Image", name: "image"} + ] + }, + { + name: "ExportImage", + description: "Export image data to file, returns true on success", + returnType: "bool", + params: [ + {type: "Image", name: "image"}, + {type: "const char *", name: "fileName"} + ] + }, + { + name: "ExportImageToMemory", + description: "Export image to memory buffer, memory must be MemFree()", + returnType: "unsigned char *", + params: [ + {type: "Image", name: "image"}, + {type: "const char *", name: "fileType"}, + {type: "int *", name: "fileSize"} + ] + }, + { + name: "ExportImageAsCode", + description: "Export image as code file defining an array of bytes, returns true on success", + returnType: "bool", + params: [ + {type: "Image", name: "image"}, + {type: "const char *", name: "fileName"} + ] + }, + { + name: "GenImageColor", + description: "Generate image: plain color", + returnType: "Image", + params: [ + {type: "int", name: "width"}, + {type: "int", name: "height"}, + {type: "Color", name: "color"} + ] + }, + { + name: "GenImageGradientLinear", + description: "Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient", + returnType: "Image", + params: [ + {type: "int", name: "width"}, + {type: "int", name: "height"}, + {type: "int", name: "direction"}, + {type: "Color", name: "start"}, + {type: "Color", name: "end"} + ] + }, + { + name: "GenImageGradientRadial", + description: "Generate image: radial gradient", + returnType: "Image", + params: [ + {type: "int", name: "width"}, + {type: "int", name: "height"}, + {type: "float", name: "density"}, + {type: "Color", name: "inner"}, + {type: "Color", name: "outer"} + ] + }, + { + name: "GenImageGradientSquare", + description: "Generate image: square gradient", + returnType: "Image", + params: [ + {type: "int", name: "width"}, + {type: "int", name: "height"}, + {type: "float", name: "density"}, + {type: "Color", name: "inner"}, + {type: "Color", name: "outer"} + ] + }, + { + name: "GenImageChecked", + description: "Generate image: checked", + returnType: "Image", + params: [ + {type: "int", name: "width"}, + {type: "int", name: "height"}, + {type: "int", name: "checksX"}, + {type: "int", name: "checksY"}, + {type: "Color", name: "col1"}, + {type: "Color", name: "col2"} + ] + }, + { + name: "GenImageWhiteNoise", + description: "Generate image: white noise", + returnType: "Image", + params: [ + {type: "int", name: "width"}, + {type: "int", name: "height"}, + {type: "float", name: "factor"} + ] + }, + { + name: "GenImagePerlinNoise", + description: "Generate image: perlin noise", + returnType: "Image", + params: [ + {type: "int", name: "width"}, + {type: "int", name: "height"}, + {type: "int", name: "offsetX"}, + {type: "int", name: "offsetY"}, + {type: "float", name: "scale"} + ] + }, + { + name: "GenImageCellular", + description: "Generate image: cellular algorithm, bigger tileSize means bigger cells", + returnType: "Image", + params: [ + {type: "int", name: "width"}, + {type: "int", name: "height"}, + {type: "int", name: "tileSize"} + ] + }, + { + name: "GenImageText", + description: "Generate image: grayscale image from text data", + returnType: "Image", + params: [ + {type: "int", name: "width"}, + {type: "int", name: "height"}, + {type: "const char *", name: "text"} + ] + }, + { + name: "ImageCopy", + description: "Create an image duplicate (useful for transformations)", + returnType: "Image", + params: [ + {type: "Image", name: "image"} + ] + }, + { + name: "ImageFromImage", + description: "Create an image from another image piece", + returnType: "Image", + params: [ + {type: "Image", name: "image"}, + {type: "Rectangle", name: "rec"} + ] + }, + { + name: "ImageFromChannel", + description: "Create an image from a selected channel of another image (GRAYSCALE)", + returnType: "Image", + params: [ + {type: "Image", name: "image"}, + {type: "int", name: "selectedChannel"} + ] + }, + { + name: "ImageText", + description: "Create an image from text (default font)", + returnType: "Image", + params: [ + {type: "const char *", name: "text"}, + {type: "int", name: "fontSize"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageTextEx", + description: "Create an image from text (custom sprite font)", + returnType: "Image", + params: [ + {type: "Font", name: "font"}, + {type: "const char *", name: "text"}, + {type: "float", name: "fontSize"}, + {type: "float", name: "spacing"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "ImageFormat", + description: "Convert image data to desired format", + returnType: "void", + params: [ + {type: "Image *", name: "image"}, + {type: "int", name: "newFormat"} + ] + }, + { + name: "ImageToPOT", + description: "Convert image to POT (power-of-two)", + returnType: "void", + params: [ + {type: "Image *", name: "image"}, + {type: "Color", name: "fill"} + ] + }, + { + name: "ImageCrop", + description: "Crop an image to a defined rectangle", + returnType: "void", + params: [ + {type: "Image *", name: "image"}, + {type: "Rectangle", name: "crop"} + ] + }, + { + name: "ImageAlphaCrop", + description: "Crop image depending on alpha value", + returnType: "void", + params: [ + {type: "Image *", name: "image"}, + {type: "float", name: "threshold"} + ] + }, + { + name: "ImageAlphaClear", + description: "Clear alpha channel to desired color", + returnType: "void", + params: [ + {type: "Image *", name: "image"}, + {type: "Color", name: "color"}, + {type: "float", name: "threshold"} + ] + }, + { + name: "ImageAlphaMask", + description: "Apply alpha mask to image", + returnType: "void", + params: [ + {type: "Image *", name: "image"}, + {type: "Image", name: "alphaMask"} + ] + }, + { + name: "ImageAlphaPremultiply", + description: "Premultiply alpha channel", + returnType: "void", + params: [ + {type: "Image *", name: "image"} + ] + }, + { + name: "ImageBlurGaussian", + description: "Apply Gaussian blur using a box blur approximation", + returnType: "void", + params: [ + {type: "Image *", name: "image"}, + {type: "int", name: "blurSize"} + ] + }, + { + name: "ImageKernelConvolution", + description: "Apply custom square convolution kernel to image", + returnType: "void", + params: [ + {type: "Image *", name: "image"}, + {type: "const float *", name: "kernel"}, + {type: "int", name: "kernelSize"} + ] + }, + { + name: "ImageResize", + description: "Resize image (Bicubic scaling algorithm)", + returnType: "void", + params: [ + {type: "Image *", name: "image"}, + {type: "int", name: "newWidth"}, + {type: "int", name: "newHeight"} + ] + }, + { + name: "ImageResizeNN", + description: "Resize image (Nearest-Neighbor scaling algorithm)", + returnType: "void", + params: [ + {type: "Image *", name: "image"}, + {type: "int", name: "newWidth"}, + {type: "int", name: "newHeight"} + ] + }, + { + name: "ImageResizeCanvas", + description: "Resize canvas and fill with color", + returnType: "void", + params: [ + {type: "Image *", name: "image"}, + {type: "int", name: "newWidth"}, + {type: "int", name: "newHeight"}, + {type: "int", name: "offsetX"}, + {type: "int", name: "offsetY"}, + {type: "Color", name: "fill"} + ] + }, + { + name: "ImageMipmaps", + description: "Compute all mipmap levels for a provided image", + returnType: "void", + params: [ + {type: "Image *", name: "image"} + ] + }, + { + name: "ImageDither", + description: "Dither image data to 16bpp or lower (Floyd-Steinberg dithering)", + returnType: "void", + params: [ + {type: "Image *", name: "image"}, + {type: "int", name: "rBpp"}, + {type: "int", name: "gBpp"}, + {type: "int", name: "bBpp"}, + {type: "int", name: "aBpp"} + ] + }, + { + name: "ImageFlipVertical", + description: "Flip image vertically", + returnType: "void", + params: [ + {type: "Image *", name: "image"} + ] + }, + { + name: "ImageFlipHorizontal", + description: "Flip image horizontally", + returnType: "void", + params: [ + {type: "Image *", name: "image"} + ] + }, + { + name: "ImageRotate", + description: "Rotate image by input angle in degrees (-359 to 359)", + returnType: "void", + params: [ + {type: "Image *", name: "image"}, + {type: "int", name: "degrees"} + ] + }, + { + name: "ImageRotateCW", + description: "Rotate image clockwise 90deg", + returnType: "void", + params: [ + {type: "Image *", name: "image"} + ] + }, + { + name: "ImageRotateCCW", + description: "Rotate image counter-clockwise 90deg", + returnType: "void", + params: [ + {type: "Image *", name: "image"} + ] + }, + { + name: "ImageColorTint", + description: "Modify image color: tint", + returnType: "void", + params: [ + {type: "Image *", name: "image"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageColorInvert", + description: "Modify image color: invert", + returnType: "void", + params: [ + {type: "Image *", name: "image"} + ] + }, + { + name: "ImageColorGrayscale", + description: "Modify image color: grayscale", + returnType: "void", + params: [ + {type: "Image *", name: "image"} + ] + }, + { + name: "ImageColorContrast", + description: "Modify image color: contrast (-100 to 100)", + returnType: "void", + params: [ + {type: "Image *", name: "image"}, + {type: "int", name: "contrast"} + ] + }, + { + name: "ImageColorBrightness", + description: "Modify image color: brightness (-255 to 255)", + returnType: "void", + params: [ + {type: "Image *", name: "image"}, + {type: "int", name: "brightness"} + ] + }, + { + name: "ImageColorReplace", + description: "Modify image color: replace color", + returnType: "void", + params: [ + {type: "Image *", name: "image"}, + {type: "Color", name: "color"}, + {type: "Color", name: "replace"} + ] + }, + { + name: "LoadImageColors", + description: "Load color data from image as a Color array (RGBA - 32bit)", + returnType: "Color *", + params: [ + {type: "Image", name: "image"} + ] + }, + { + name: "LoadImagePalette", + description: "Load colors palette from image as a Color array (RGBA - 32bit)", + returnType: "Color *", + params: [ + {type: "Image", name: "image"}, + {type: "int", name: "maxPaletteSize"}, + {type: "int *", name: "colorCount"} + ] + }, + { + name: "UnloadImageColors", + description: "Unload color data loaded with LoadImageColors()", + returnType: "void", + params: [ + {type: "Color *", name: "colors"} + ] + }, + { + name: "UnloadImagePalette", + description: "Unload colors palette loaded with LoadImagePalette()", + returnType: "void", + params: [ + {type: "Color *", name: "colors"} + ] + }, + { + name: "GetImageAlphaBorder", + description: "Get image alpha border rectangle", + returnType: "Rectangle", + params: [ + {type: "Image", name: "image"}, + {type: "float", name: "threshold"} + ] + }, + { + name: "GetImageColor", + description: "Get image pixel color at (x, y) position", + returnType: "Color", + params: [ + {type: "Image", name: "image"}, + {type: "int", name: "x"}, + {type: "int", name: "y"} + ] + }, + { + name: "ImageClearBackground", + description: "Clear image background with given color", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageDrawPixel", + description: "Draw pixel within an image", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "int", name: "posX"}, + {type: "int", name: "posY"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageDrawPixelV", + description: "Draw pixel within an image (Vector version)", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "Vector2", name: "position"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageDrawLine", + description: "Draw line within an image", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "int", name: "startPosX"}, + {type: "int", name: "startPosY"}, + {type: "int", name: "endPosX"}, + {type: "int", name: "endPosY"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageDrawLineV", + description: "Draw line within an image (Vector version)", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "Vector2", name: "start"}, + {type: "Vector2", name: "end"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageDrawLineEx", + description: "Draw a line defining thickness within an image", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "Vector2", name: "start"}, + {type: "Vector2", name: "end"}, + {type: "int", name: "thick"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageDrawCircle", + description: "Draw a filled circle within an image", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "int", name: "centerX"}, + {type: "int", name: "centerY"}, + {type: "int", name: "radius"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageDrawCircleV", + description: "Draw a filled circle within an image (Vector version)", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "Vector2", name: "center"}, + {type: "int", name: "radius"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageDrawCircleLines", + description: "Draw circle outline within an image", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "int", name: "centerX"}, + {type: "int", name: "centerY"}, + {type: "int", name: "radius"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageDrawCircleLinesV", + description: "Draw circle outline within an image (Vector version)", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "Vector2", name: "center"}, + {type: "int", name: "radius"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageDrawRectangle", + description: "Draw rectangle within an image", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "int", name: "posX"}, + {type: "int", name: "posY"}, + {type: "int", name: "width"}, + {type: "int", name: "height"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageDrawRectangleV", + description: "Draw rectangle within an image (Vector version)", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "Vector2", name: "position"}, + {type: "Vector2", name: "size"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageDrawRectangleRec", + description: "Draw rectangle within an image", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "Rectangle", name: "rec"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageDrawRectangleLines", + description: "Draw rectangle lines within an image", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "int", name: "posX"}, + {type: "int", name: "posY"}, + {type: "int", name: "width"}, + {type: "int", name: "height"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageDrawRectangleLinesEx", + description: "Draw rectangle lines within an image with extended parameters", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "Rectangle", name: "rec"}, + {type: "int", name: "thick"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageDrawTriangle", + description: "Draw triangle within an image", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "Vector2", name: "v1"}, + {type: "Vector2", name: "v2"}, + {type: "Vector2", name: "v3"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageDrawTriangleGradient", + description: "Draw triangle with interpolated colors within an image", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "Vector2", name: "v1"}, + {type: "Vector2", name: "v2"}, + {type: "Vector2", name: "v3"}, + {type: "Color", name: "c1"}, + {type: "Color", name: "c2"}, + {type: "Color", name: "c3"} + ] + }, + { + name: "ImageDrawTriangleLines", + description: "Draw triangle outline within an image", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "Vector2", name: "v1"}, + {type: "Vector2", name: "v2"}, + {type: "Vector2", name: "v3"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageDrawTriangleFan", + description: "Draw a triangle fan defined by points within an image (first vertex is the center)", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "const Vector2 *", name: "points"}, + {type: "int", name: "pointCount"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageDrawTriangleStrip", + description: "Draw a triangle strip defined by points within an image", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "const Vector2 *", name: "points"}, + {type: "int", name: "pointCount"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageDraw", + description: "Draw a source image within a destination image (tint applied to source)", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "Image", name: "src"}, + {type: "Rectangle", name: "srcRec"}, + {type: "Rectangle", name: "dstRec"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "ImageDrawText", + description: "Draw text (using default font) within an image (destination)", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "const char *", name: "text"}, + {type: "int", name: "posX"}, + {type: "int", name: "posY"}, + {type: "int", name: "fontSize"}, + {type: "Color", name: "color"} + ] + }, + { + name: "ImageDrawTextEx", + description: "Draw text (custom sprite font) within an image (destination)", + returnType: "void", + params: [ + {type: "Image *", name: "dst"}, + {type: "Font", name: "font"}, + {type: "const char *", name: "text"}, + {type: "Vector2", name: "position"}, + {type: "float", name: "fontSize"}, + {type: "float", name: "spacing"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "LoadTexture", + description: "Load texture from file into GPU memory (VRAM)", + returnType: "Texture2D", + params: [ + {type: "const char *", name: "fileName"} + ] + }, + { + name: "LoadTextureFromImage", + description: "Load texture from image data", + returnType: "Texture2D", + params: [ + {type: "Image", name: "image"} + ] + }, + { + name: "LoadTextureCubemap", + description: "Load cubemap from image, multiple image cubemap layouts supported", + returnType: "TextureCubemap", + params: [ + {type: "Image", name: "image"}, + {type: "int", name: "layout"} + ] + }, + { + name: "LoadRenderTexture", + description: "Load texture for rendering (framebuffer)", + returnType: "RenderTexture2D", + params: [ + {type: "int", name: "width"}, + {type: "int", name: "height"} + ] + }, + { + name: "IsTextureValid", + description: "Check if texture is valid (loaded in GPU)", + returnType: "bool", + params: [ + {type: "Texture2D", name: "texture"} + ] + }, + { + name: "UnloadTexture", + description: "Unload texture from GPU memory (VRAM)", + returnType: "void", + params: [ + {type: "Texture2D", name: "texture"} + ] + }, + { + name: "IsRenderTextureValid", + description: "Check if render texture is valid (loaded in GPU)", + returnType: "bool", + params: [ + {type: "RenderTexture2D", name: "target"} + ] + }, + { + name: "UnloadRenderTexture", + description: "Unload render texture from GPU memory (VRAM)", + returnType: "void", + params: [ + {type: "RenderTexture2D", name: "target"} + ] + }, + { + name: "UpdateTexture", + description: "Update GPU texture with new data (pixels should be able to fill texture)", + returnType: "void", + params: [ + {type: "Texture2D", name: "texture"}, + {type: "const void *", name: "pixels"} + ] + }, + { + name: "UpdateTextureRec", + description: "Update GPU texture rectangle with new data (pixels and rec should fit in texture)", + returnType: "void", + params: [ + {type: "Texture2D", name: "texture"}, + {type: "Rectangle", name: "rec"}, + {type: "const void *", name: "pixels"} + ] + }, + { + name: "GenTextureMipmaps", + description: "Generate GPU mipmaps for a texture", + returnType: "void", + params: [ + {type: "Texture2D *", name: "texture"} + ] + }, + { + name: "SetTextureFilter", + description: "Set texture scaling filter mode", + returnType: "void", + params: [ + {type: "Texture2D", name: "texture"}, + {type: "int", name: "filter"} + ] + }, + { + name: "SetTextureWrap", + description: "Set texture wrapping mode", + returnType: "void", + params: [ + {type: "Texture2D", name: "texture"}, + {type: "int", name: "wrap"} + ] + }, + { + name: "DrawTexture", + description: "Draw a Texture2D", + returnType: "void", + params: [ + {type: "Texture2D", name: "texture"}, + {type: "int", name: "posX"}, + {type: "int", name: "posY"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "DrawTextureV", + description: "Draw a Texture2D with position defined as Vector2", + returnType: "void", + params: [ + {type: "Texture2D", name: "texture"}, + {type: "Vector2", name: "position"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "DrawTextureEx", + description: "Draw a Texture2D with extended parameters", + returnType: "void", + params: [ + {type: "Texture2D", name: "texture"}, + {type: "Vector2", name: "position"}, + {type: "float", name: "rotation"}, + {type: "float", name: "scale"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "DrawTextureRec", + description: "Draw a part of a texture defined by a rectangle", + returnType: "void", + params: [ + {type: "Texture2D", name: "texture"}, + {type: "Rectangle", name: "rec"}, + {type: "Vector2", name: "position"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "DrawTexturePro", + description: "Draw a part of a texture defined by a source rectangle to destination rectangle, with scaling and rotation", + returnType: "void", + params: [ + {type: "Texture2D", name: "texture"}, + {type: "Rectangle", name: "srcrec"}, + {type: "Rectangle", name: "dstrec"}, + {type: "Vector2", name: "origin"}, + {type: "float", name: "rotation"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "DrawTextureNPatch", + description: "Draw a texture (or part of it) that stretches or shrinks nicely", + returnType: "void", + params: [ + {type: "Texture2D", name: "texture"}, + {type: "NPatchInfo", name: "nPatchInfo"}, + {type: "Rectangle", name: "dstrec"}, + {type: "Vector2", name: "origin"}, + {type: "float", name: "rotation"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "ColorIsEqual", + description: "Check if two colors are equal", + returnType: "bool", + params: [ + {type: "Color", name: "col1"}, + {type: "Color", name: "col2"} + ] + }, + { + name: "Fade", + description: "Get color with alpha applied, alpha goes from 0.0f to 1.0f", + returnType: "Color", + params: [ + {type: "Color", name: "color"}, + {type: "float", name: "alpha"} + ] + }, + { + name: "ColorToInt", + description: "Get hexadecimal value for a Color (0xRRGGBBAA)", + returnType: "int", + params: [ + {type: "Color", name: "color"} + ] + }, + { + name: "ColorNormalize", + description: "Get Color normalized as float [0..1]", + returnType: "Vector4", + params: [ + {type: "Color", name: "color"} + ] + }, + { + name: "ColorFromNormalized", + description: "Get Color from normalized values [0..1]", + returnType: "Color", + params: [ + {type: "Vector4", name: "normalized"} + ] + }, + { + name: "ColorToHSV", + description: "Get HSV values for a Color, hue [0..360], saturation/value [0..1]", + returnType: "Vector3", + params: [ + {type: "Color", name: "color"} + ] + }, + { + name: "ColorFromHSV", + description: "Get a Color from HSV values, hue [0..360], saturation/value [0..1]", + returnType: "Color", + params: [ + {type: "float", name: "hue"}, + {type: "float", name: "saturation"}, + {type: "float", name: "value"} + ] + }, + { + name: "ColorTint", + description: "Get color multiplied with another color", + returnType: "Color", + params: [ + {type: "Color", name: "color"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "ColorBrightness", + description: "Get color with brightness correction, brightness factor goes from -1.0f to 1.0f", + returnType: "Color", + params: [ + {type: "Color", name: "color"}, + {type: "float", name: "factor"} + ] + }, + { + name: "ColorContrast", + description: "Get color with contrast correction, contrast values between -1.0f and 1.0f", + returnType: "Color", + params: [ + {type: "Color", name: "color"}, + {type: "float", name: "contrast"} + ] + }, + { + name: "ColorAlpha", + description: "Get color with alpha applied, alpha goes from 0.0f to 1.0f", + returnType: "Color", + params: [ + {type: "Color", name: "color"}, + {type: "float", name: "alpha"} + ] + }, + { + name: "ColorAlphaBlend", + description: "Get src alpha-blended into dst color with tint", + returnType: "Color", + params: [ + {type: "Color", name: "dst"}, + {type: "Color", name: "src"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "ColorLerp", + description: "Get color lerp interpolation between two colors, factor [0.0f..1.0f]", + returnType: "Color", + params: [ + {type: "Color", name: "color1"}, + {type: "Color", name: "color2"}, + {type: "float", name: "factor"} + ] + }, + { + name: "GetColor", + description: "Get Color structure from hexadecimal value", + returnType: "Color", + params: [ + {type: "unsigned int", name: "hexValue"} + ] + }, + { + name: "GetPixelColor", + description: "Get Color from a source pixel pointer of certain format", + returnType: "Color", + params: [ + {type: "const void *", name: "srcPtr"}, + {type: "int", name: "format"} + ] + }, + { + name: "SetPixelColor", + description: "Set color formatted into destination pixel pointer", + returnType: "void", + params: [ + {type: "void *", name: "dstPtr"}, + {type: "Color", name: "color"}, + {type: "int", name: "format"} + ] + }, + { + name: "GetPixelDataSize", + description: "Get pixel data size in bytes for certain format", + returnType: "int", + params: [ + {type: "int", name: "width"}, + {type: "int", name: "height"}, + {type: "int", name: "format"} + ] + }, + { + name: "GetFontDefault", + description: "Get the default Font", + returnType: "Font" + }, + { + name: "LoadFont", + description: "Load font from file into GPU memory (VRAM)", + returnType: "Font", + params: [ + {type: "const char *", name: "fileName"} + ] + }, + { + name: "LoadFontEx", + description: "Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height", + returnType: "Font", + params: [ + {type: "const char *", name: "fileName"}, + {type: "int", name: "fontSize"}, + {type: "const int *", name: "codepoints"}, + {type: "int", name: "codepointCount"} + ] + }, + { + name: "LoadFontFromImage", + description: "Load font from Image (XNA style)", + returnType: "Font", + params: [ + {type: "Image", name: "image"}, + {type: "Color", name: "key"}, + {type: "int", name: "firstChar"} + ] + }, + { + name: "LoadFontFromMemory", + description: "Load font from memory buffer, fileType refers to extension: i.e. '.ttf'", + returnType: "Font", + params: [ + {type: "const char *", name: "fileType"}, + {type: "const unsigned char *", name: "fileData"}, + {type: "int", name: "dataSize"}, + {type: "int", name: "fontSize"}, + {type: "const int *", name: "codepoints"}, + {type: "int", name: "codepointCount"} + ] + }, + { + name: "IsFontValid", + description: "Check if font is valid (font data loaded, WARNING: GPU texture not checked)", + returnType: "bool", + params: [ + {type: "Font", name: "font"} + ] + }, + { + name: "LoadFontData", + description: "Load font data for further use", + returnType: "GlyphInfo *", + params: [ + {type: "const unsigned char *", name: "fileData"}, + {type: "int", name: "dataSize"}, + {type: "int", name: "fontSize"}, + {type: "const int *", name: "codepoints"}, + {type: "int", name: "codepointCount"}, + {type: "int", name: "type"}, + {type: "int *", name: "glyphCount"} + ] + }, + { + name: "GenImageFontAtlas", + description: "Generate image font atlas using chars info", + returnType: "Image", + params: [ + {type: "const GlyphInfo *", name: "glyphs"}, + {type: "Rectangle **", name: "glyphRecs"}, + {type: "int", name: "glyphCount"}, + {type: "int", name: "fontSize"}, + {type: "int", name: "padding"}, + {type: "int", name: "packMethod"} + ] + }, + { + name: "UnloadFontData", + description: "Unload font chars info data (RAM)", + returnType: "void", + params: [ + {type: "GlyphInfo *", name: "glyphs"}, + {type: "int", name: "glyphCount"} + ] + }, + { + name: "UnloadFont", + description: "Unload font from GPU memory (VRAM)", + returnType: "void", + params: [ + {type: "Font", name: "font"} + ] + }, + { + name: "ExportFontAsCode", + description: "Export font as code file, returns true on success", + returnType: "bool", + params: [ + {type: "Font", name: "font"}, + {type: "const char *", name: "fileName"} + ] + }, + { + name: "DrawFPS", + description: "Draw current FPS", + returnType: "void", + params: [ + {type: "int", name: "posX"}, + {type: "int", name: "posY"} + ] + }, + { + name: "DrawText", + description: "Draw text (using default font)", + returnType: "void", + params: [ + {type: "const char *", name: "text"}, + {type: "int", name: "posX"}, + {type: "int", name: "posY"}, + {type: "int", name: "fontSize"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawTextEx", + description: "Draw text using font and additional parameters", + returnType: "void", + params: [ + {type: "Font", name: "font"}, + {type: "const char *", name: "text"}, + {type: "Vector2", name: "position"}, + {type: "float", name: "fontSize"}, + {type: "float", name: "spacing"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "DrawTextPro", + description: "Draw text using Font and pro parameters (rotation)", + returnType: "void", + params: [ + {type: "Font", name: "font"}, + {type: "const char *", name: "text"}, + {type: "Vector2", name: "position"}, + {type: "Vector2", name: "origin"}, + {type: "float", name: "rotation"}, + {type: "float", name: "fontSize"}, + {type: "float", name: "spacing"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "DrawTextCodepoint", + description: "Draw one character (codepoint)", + returnType: "void", + params: [ + {type: "Font", name: "font"}, + {type: "int", name: "codepoint"}, + {type: "Vector2", name: "position"}, + {type: "float", name: "fontSize"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "DrawTextCodepoints", + description: "Draw multiple characters (codepoint)", + returnType: "void", + params: [ + {type: "Font", name: "font"}, + {type: "const int *", name: "codepoints"}, + {type: "int", name: "codepointCount"}, + {type: "Vector2", name: "position"}, + {type: "float", name: "fontSize"}, + {type: "float", name: "spacing"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "SetTextLineSpacing", + description: "Set vertical line spacing when drawing with line-breaks", + returnType: "void", + params: [ + {type: "int", name: "spacing"} + ] + }, + { + name: "MeasureText", + description: "Measure string width for default font", + returnType: "int", + params: [ + {type: "const char *", name: "text"}, + {type: "int", name: "fontSize"} + ] + }, + { + name: "MeasureTextEx", + description: "Measure string size for Font", + returnType: "Vector2", + params: [ + {type: "Font", name: "font"}, + {type: "const char *", name: "text"}, + {type: "float", name: "fontSize"}, + {type: "float", name: "spacing"} + ] + }, + { + name: "MeasureTextCodepoints", + description: "Measure string size for an existing array of codepoints for Font", + returnType: "Vector2", + params: [ + {type: "Font", name: "font"}, + {type: "const int *", name: "codepoints"}, + {type: "int", name: "length"}, + {type: "float", name: "fontSize"}, + {type: "float", name: "spacing"} + ] + }, + { + name: "GetGlyphIndex", + description: "Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found", + returnType: "int", + params: [ + {type: "Font", name: "font"}, + {type: "int", name: "codepoint"} + ] + }, + { + name: "GetGlyphInfo", + description: "Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found", + returnType: "GlyphInfo", + params: [ + {type: "Font", name: "font"}, + {type: "int", name: "codepoint"} + ] + }, + { + name: "GetGlyphAtlasRec", + description: "Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found", + returnType: "Rectangle", + params: [ + {type: "Font", name: "font"}, + {type: "int", name: "codepoint"} + ] + }, + { + name: "LoadUTF8", + description: "Load UTF-8 text encoded from codepoints array", + returnType: "char *", + params: [ + {type: "const int *", name: "codepoints"}, + {type: "int", name: "length"} + ] + }, + { + name: "UnloadUTF8", + description: "Unload UTF-8 text encoded from codepoints array", + returnType: "void", + params: [ + {type: "char *", name: "text"} + ] + }, + { + name: "LoadCodepoints", + description: "Load all codepoints from a UTF-8 text string, codepoints count returned by parameter", + returnType: "int *", + params: [ + {type: "const char *", name: "text"}, + {type: "int *", name: "count"} + ] + }, + { + name: "UnloadCodepoints", + description: "Unload codepoints data from memory", + returnType: "void", + params: [ + {type: "int *", name: "codepoints"} + ] + }, + { + name: "GetCodepointCount", + description: "Get total number of codepoints in a UTF-8 encoded string", + returnType: "int", + params: [ + {type: "const char *", name: "text"} + ] + }, + { + name: "GetCodepoint", + description: "Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure", + returnType: "int", + params: [ + {type: "const char *", name: "text"}, + {type: "int *", name: "codepointSize"} + ] + }, + { + name: "GetCodepointNext", + description: "Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure", + returnType: "int", + params: [ + {type: "const char *", name: "text"}, + {type: "int *", name: "codepointSize"} + ] + }, + { + name: "GetCodepointPrevious", + description: "Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure", + returnType: "int", + params: [ + {type: "const char *", name: "text"}, + {type: "int *", name: "codepointSize"} + ] + }, + { + name: "CodepointToUTF8", + description: "Encode one codepoint into UTF-8 byte array (array length returned as parameter)", + returnType: "const char *", + params: [ + {type: "int", name: "codepoint"}, + {type: "int *", name: "utf8Size"} + ] + }, + { + name: "LoadTextLines", + description: "Load text as separate lines ('\\n')", + returnType: "char **", + params: [ + {type: "const char *", name: "text"}, + {type: "int *", name: "count"} + ] + }, + { + name: "UnloadTextLines", + description: "Unload text lines", + returnType: "void", + params: [ + {type: "char **", name: "text"}, + {type: "int", name: "lineCount"} + ] + }, + { + name: "TextCopy", + description: "Copy one string to another, returns bytes copied", + returnType: "int", + params: [ + {type: "char *", name: "dst"}, + {type: "const char *", name: "src"} + ] + }, + { + name: "TextIsEqual", + description: "Check if two text strings are equal", + returnType: "bool", + params: [ + {type: "const char *", name: "text1"}, + {type: "const char *", name: "text2"} + ] + }, + { + name: "TextLength", + description: "Get text length, checks for '\\0' ending", + returnType: "unsigned int", + params: [ + {type: "const char *", name: "text"} + ] + }, + { + name: "TextFormat", + description: "Text formatting with variables (sprintf() style)", + returnType: "const char *", + params: [ + {type: "const char *", name: "text"}, + {type: "...", name: "args"} + ] + }, + { + name: "TextSubtext", + description: "Get a piece of a text string", + returnType: "const char *", + params: [ + {type: "const char *", name: "text"}, + {type: "int", name: "position"}, + {type: "int", name: "length"} + ] + }, + { + name: "TextRemoveSpaces", + description: "Remove text spaces, concat words", + returnType: "const char *", + params: [ + {type: "const char *", name: "text"} + ] + }, + { + name: "GetTextBetween", + description: "Get text between two strings", + returnType: "char *", + params: [ + {type: "const char *", name: "text"}, + {type: "const char *", name: "begin"}, + {type: "const char *", name: "end"} + ] + }, + { + name: "TextReplace", + description: "Replace text string with new string", + returnType: "char *", + params: [ + {type: "const char *", name: "text"}, + {type: "const char *", name: "search"}, + {type: "const char *", name: "replacement"} + ] + }, + { + name: "TextReplaceAlloc", + description: "Replace text string with new string, memory must be MemFree()", + returnType: "char *", + params: [ + {type: "const char *", name: "text"}, + {type: "const char *", name: "search"}, + {type: "const char *", name: "replacement"} + ] + }, + { + name: "TextReplaceBetween", + description: "Replace text between two specific strings", + returnType: "char *", + params: [ + {type: "const char *", name: "text"}, + {type: "const char *", name: "begin"}, + {type: "const char *", name: "end"}, + {type: "const char *", name: "replacement"} + ] + }, + { + name: "TextReplaceBetweenAlloc", + description: "Replace text between two specific strings, memory must be MemFree()", + returnType: "char *", + params: [ + {type: "const char *", name: "text"}, + {type: "const char *", name: "begin"}, + {type: "const char *", name: "end"}, + {type: "const char *", name: "replacement"} + ] + }, + { + name: "TextInsert", + description: "Insert text in a defined byte position", + returnType: "char *", + params: [ + {type: "const char *", name: "text"}, + {type: "const char *", name: "insert"}, + {type: "int", name: "position"} + ] + }, + { + name: "TextInsertAlloc", + description: "Insert text in a defined byte position, memory must be MemFree()", + returnType: "char *", + params: [ + {type: "const char *", name: "text"}, + {type: "const char *", name: "insert"}, + {type: "int", name: "position"} + ] + }, + { + name: "TextJoin", + description: "Join text strings with delimiter", + returnType: "char *", + params: [ + {type: "char **", name: "textList"}, + {type: "int", name: "count"}, + {type: "const char *", name: "delimiter"} + ] + }, + { + name: "TextSplit", + description: "Split text into multiple strings, using MAX_TEXTSPLIT_COUNT static strings", + returnType: "char **", + params: [ + {type: "const char *", name: "text"}, + {type: "char", name: "delimiter"}, + {type: "int *", name: "count"} + ] + }, + { + name: "TextAppend", + description: "Append text at specific position and move cursor", + returnType: "void", + params: [ + {type: "char *", name: "text"}, + {type: "const char *", name: "append"}, + {type: "int *", name: "position"} + ] + }, + { + name: "TextFindIndex", + description: "Find first text occurrence within a string, -1 if not found", + returnType: "int", + params: [ + {type: "const char *", name: "text"}, + {type: "const char *", name: "search"} + ] + }, + { + name: "TextToUpper", + description: "Get upper case version of provided string", + returnType: "char *", + params: [ + {type: "const char *", name: "text"} + ] + }, + { + name: "TextToLower", + description: "Get lower case version of provided string", + returnType: "char *", + params: [ + {type: "const char *", name: "text"} + ] + }, + { + name: "TextToPascal", + description: "Get Pascal case notation version of provided string", + returnType: "char *", + params: [ + {type: "const char *", name: "text"} + ] + }, + { + name: "TextToSnake", + description: "Get Snake case notation version of provided string", + returnType: "char *", + params: [ + {type: "const char *", name: "text"} + ] + }, + { + name: "TextToCamel", + description: "Get Camel case notation version of provided string", + returnType: "char *", + params: [ + {type: "const char *", name: "text"} + ] + }, + { + name: "TextToInteger", + description: "Get integer value from text", + returnType: "int", + params: [ + {type: "const char *", name: "text"} + ] + }, + { + name: "TextToFloat", + description: "Get float value from text", + returnType: "float", + params: [ + {type: "const char *", name: "text"} + ] + }, + { + name: "DrawLine3D", + description: "Draw a line in 3D world space", + returnType: "void", + params: [ + {type: "Vector3", name: "startPos"}, + {type: "Vector3", name: "endPos"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawPoint3D", + description: "Draw a point in 3D space, actually a small line", + returnType: "void", + params: [ + {type: "Vector3", name: "position"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawCircle3D", + description: "Draw a circle in 3D world space", + returnType: "void", + params: [ + {type: "Vector3", name: "center"}, + {type: "float", name: "radius"}, + {type: "Vector3", name: "rotationAxis"}, + {type: "float", name: "rotationAngle"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawTriangle3D", + description: "Draw a color-filled triangle (vertex in counter-clockwise order!)", + returnType: "void", + params: [ + {type: "Vector3", name: "v1"}, + {type: "Vector3", name: "v2"}, + {type: "Vector3", name: "v3"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawTriangleStrip3D", + description: "Draw a triangle strip defined by points", + returnType: "void", + params: [ + {type: "const Vector3 *", name: "points"}, + {type: "int", name: "pointCount"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawCube", + description: "Draw cube", + returnType: "void", + params: [ + {type: "Vector3", name: "position"}, + {type: "float", name: "width"}, + {type: "float", name: "height"}, + {type: "float", name: "length"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawCubeV", + description: "Draw cube (Vector version)", + returnType: "void", + params: [ + {type: "Vector3", name: "position"}, + {type: "Vector3", name: "size"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawCubeWires", + description: "Draw cube wires", + returnType: "void", + params: [ + {type: "Vector3", name: "position"}, + {type: "float", name: "width"}, + {type: "float", name: "height"}, + {type: "float", name: "length"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawCubeWiresV", + description: "Draw cube wires (Vector version)", + returnType: "void", + params: [ + {type: "Vector3", name: "position"}, + {type: "Vector3", name: "size"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawSphere", + description: "Draw sphere", + returnType: "void", + params: [ + {type: "Vector3", name: "centerPos"}, + {type: "float", name: "radius"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawSphereEx", + description: "Draw sphere with extended parameters", + returnType: "void", + params: [ + {type: "Vector3", name: "centerPos"}, + {type: "float", name: "radius"}, + {type: "int", name: "rings"}, + {type: "int", name: "slices"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawSphereWires", + description: "Draw sphere wires", + returnType: "void", + params: [ + {type: "Vector3", name: "centerPos"}, + {type: "float", name: "radius"}, + {type: "int", name: "rings"}, + {type: "int", name: "slices"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawCylinder", + description: "Draw a cylinder/cone", + returnType: "void", + params: [ + {type: "Vector3", name: "position"}, + {type: "float", name: "radiusTop"}, + {type: "float", name: "radiusBottom"}, + {type: "float", name: "height"}, + {type: "int", name: "sides"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawCylinderEx", + description: "Draw a cylinder with base at startPos and top at endPos", + returnType: "void", + params: [ + {type: "Vector3", name: "startPos"}, + {type: "Vector3", name: "endPos"}, + {type: "float", name: "startRadius"}, + {type: "float", name: "endRadius"}, + {type: "int", name: "sides"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawCylinderWires", + description: "Draw a cylinder/cone wires", + returnType: "void", + params: [ + {type: "Vector3", name: "position"}, + {type: "float", name: "radiusTop"}, + {type: "float", name: "radiusBottom"}, + {type: "float", name: "height"}, + {type: "int", name: "sides"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawCylinderWiresEx", + description: "Draw a cylinder wires with base at startPos and top at endPos", + returnType: "void", + params: [ + {type: "Vector3", name: "startPos"}, + {type: "Vector3", name: "endPos"}, + {type: "float", name: "startRadius"}, + {type: "float", name: "endRadius"}, + {type: "int", name: "sides"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawCapsule", + description: "Draw a capsule with the center of its sphere caps at startPos and endPos", + returnType: "void", + params: [ + {type: "Vector3", name: "startPos"}, + {type: "Vector3", name: "endPos"}, + {type: "float", name: "radius"}, + {type: "int", name: "rings"}, + {type: "int", name: "slices"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawCapsuleWires", + description: "Draw capsule wireframe with the center of its sphere caps at startPos and endPos", + returnType: "void", + params: [ + {type: "Vector3", name: "startPos"}, + {type: "Vector3", name: "endPos"}, + {type: "float", name: "radius"}, + {type: "int", name: "rings"}, + {type: "int", name: "slices"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawPlane", + description: "Draw a plane XZ", + returnType: "void", + params: [ + {type: "Vector3", name: "centerPos"}, + {type: "Vector2", name: "size"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawRay", + description: "Draw a ray line", + returnType: "void", + params: [ + {type: "Ray", name: "ray"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawGrid", + description: "Draw a grid (centered at (0, 0, 0))", + returnType: "void", + params: [ + {type: "int", name: "slices"}, + {type: "float", name: "spacing"} + ] + }, + { + name: "LoadModel", + description: "Load model from files (meshes and materials)", + returnType: "Model", + params: [ + {type: "const char *", name: "fileName"} + ] + }, + { + name: "LoadModelFromMesh", + description: "Load model from generated mesh (default material)", + returnType: "Model", + params: [ + {type: "Mesh", name: "mesh"} + ] + }, + { + name: "IsModelValid", + description: "Check if model is valid (loaded in GPU, VAO/VBOs)", + returnType: "bool", + params: [ + {type: "Model", name: "model"} + ] + }, + { + name: "UnloadModel", + description: "Unload model (including meshes) from memory (RAM and/or VRAM)", + returnType: "void", + params: [ + {type: "Model", name: "model"} + ] + }, + { + name: "GetModelBoundingBox", + description: "Compute model bounding box limits (considers all meshes)", + returnType: "BoundingBox", + params: [ + {type: "Model", name: "model"} + ] + }, + { + name: "DrawModel", + description: "Draw a model (with texture if set)", + returnType: "void", + params: [ + {type: "Model", name: "model"}, + {type: "Vector3", name: "position"}, + {type: "float", name: "scale"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "DrawModelEx", + description: "Draw a model with extended parameters", + returnType: "void", + params: [ + {type: "Model", name: "model"}, + {type: "Vector3", name: "position"}, + {type: "Vector3", name: "rotationAxis"}, + {type: "float", name: "rotationAngle"}, + {type: "Vector3", name: "scale"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "DrawModelWires", + description: "Draw a model wires (with texture if set)", + returnType: "void", + params: [ + {type: "Model", name: "model"}, + {type: "Vector3", name: "position"}, + {type: "float", name: "scale"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "DrawModelWiresEx", + description: "Draw a model wires (with texture if set) with extended parameters", + returnType: "void", + params: [ + {type: "Model", name: "model"}, + {type: "Vector3", name: "position"}, + {type: "Vector3", name: "rotationAxis"}, + {type: "float", name: "rotationAngle"}, + {type: "Vector3", name: "scale"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "DrawBoundingBox", + description: "Draw bounding box (wires)", + returnType: "void", + params: [ + {type: "BoundingBox", name: "box"}, + {type: "Color", name: "color"} + ] + }, + { + name: "DrawBillboard", + description: "Draw a billboard texture", + returnType: "void", + params: [ + {type: "Camera", name: "camera"}, + {type: "Texture2D", name: "texture"}, + {type: "Vector3", name: "position"}, + {type: "float", name: "scale"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "DrawBillboardRec", + description: "Draw a billboard texture defined by rectangle", + returnType: "void", + params: [ + {type: "Camera", name: "camera"}, + {type: "Texture2D", name: "texture"}, + {type: "Rectangle", name: "rec"}, + {type: "Vector3", name: "position"}, + {type: "Vector2", name: "size"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "DrawBillboardPro", + description: "Draw a billboard texture defined by source rectangle with scaling and rotation", + returnType: "void", + params: [ + {type: "Camera", name: "camera"}, + {type: "Texture2D", name: "texture"}, + {type: "Rectangle", name: "rec"}, + {type: "Vector3", name: "position"}, + {type: "Vector3", name: "up"}, + {type: "Vector2", name: "size"}, + {type: "Vector2", name: "origin"}, + {type: "float", name: "rotation"}, + {type: "Color", name: "tint"} + ] + }, + { + name: "UploadMesh", + description: "Upload mesh vertex data in GPU and provide VAO/VBO ids", + returnType: "void", + params: [ + {type: "Mesh *", name: "mesh"}, + {type: "bool", name: "dynamic"} + ] + }, + { + name: "UpdateMeshBuffer", + description: "Update mesh vertex data in GPU for a specific buffer index", + returnType: "void", + params: [ + {type: "Mesh", name: "mesh"}, + {type: "int", name: "index"}, + {type: "const void *", name: "data"}, + {type: "int", name: "dataSize"}, + {type: "int", name: "offset"} + ] + }, + { + name: "UnloadMesh", + description: "Unload mesh data from CPU and GPU", + returnType: "void", + params: [ + {type: "Mesh", name: "mesh"} + ] + }, + { + name: "DrawMesh", + description: "Draw a 3d mesh with material and transform", + returnType: "void", + params: [ + {type: "Mesh", name: "mesh"}, + {type: "Material", name: "material"}, + {type: "Matrix", name: "transform"} + ] + }, + { + name: "DrawMeshInstanced", + description: "Draw multiple mesh instances with material and different transforms", + returnType: "void", + params: [ + {type: "Mesh", name: "mesh"}, + {type: "Material", name: "material"}, + {type: "const Matrix *", name: "transforms"}, + {type: "int", name: "instances"} + ] + }, + { + name: "GetMeshBoundingBox", + description: "Compute mesh bounding box limits", + returnType: "BoundingBox", + params: [ + {type: "Mesh", name: "mesh"} + ] + }, + { + name: "GenMeshTangents", + description: "Compute mesh tangents", + returnType: "void", + params: [ + {type: "Mesh *", name: "mesh"} + ] + }, + { + name: "ExportMesh", + description: "Export mesh data to file, returns true on success", + returnType: "bool", + params: [ + {type: "Mesh", name: "mesh"}, + {type: "const char *", name: "fileName"} + ] + }, + { + name: "ExportMeshAsCode", + description: "Export mesh as code file (.h) defining multiple arrays of vertex attributes", + returnType: "bool", + params: [ + {type: "Mesh", name: "mesh"}, + {type: "const char *", name: "fileName"} + ] + }, + { + name: "GenMeshPoly", + description: "Generate polygonal mesh", + returnType: "Mesh", + params: [ + {type: "int", name: "sides"}, + {type: "float", name: "radius"} + ] + }, + { + name: "GenMeshPlane", + description: "Generate plane mesh (with subdivisions)", + returnType: "Mesh", + params: [ + {type: "float", name: "width"}, + {type: "float", name: "length"}, + {type: "int", name: "resX"}, + {type: "int", name: "resZ"} + ] + }, + { + name: "GenMeshCube", + description: "Generate cuboid mesh", + returnType: "Mesh", + params: [ + {type: "float", name: "width"}, + {type: "float", name: "height"}, + {type: "float", name: "length"} + ] + }, + { + name: "GenMeshSphere", + description: "Generate sphere mesh (standard sphere)", + returnType: "Mesh", + params: [ + {type: "float", name: "radius"}, + {type: "int", name: "rings"}, + {type: "int", name: "slices"} + ] + }, + { + name: "GenMeshHemiSphere", + description: "Generate half-sphere mesh (no bottom cap)", + returnType: "Mesh", + params: [ + {type: "float", name: "radius"}, + {type: "int", name: "rings"}, + {type: "int", name: "slices"} + ] + }, + { + name: "GenMeshCylinder", + description: "Generate cylinder mesh", + returnType: "Mesh", + params: [ + {type: "float", name: "radius"}, + {type: "float", name: "height"}, + {type: "int", name: "slices"} + ] + }, + { + name: "GenMeshCone", + description: "Generate cone/pyramid mesh", + returnType: "Mesh", + params: [ + {type: "float", name: "radius"}, + {type: "float", name: "height"}, + {type: "int", name: "slices"} + ] + }, + { + name: "GenMeshTorus", + description: "Generate torus mesh", + returnType: "Mesh", + params: [ + {type: "float", name: "radius"}, + {type: "float", name: "size"}, + {type: "int", name: "radSeg"}, + {type: "int", name: "sides"} + ] + }, + { + name: "GenMeshKnot", + description: "Generate trefoil knot mesh", + returnType: "Mesh", + params: [ + {type: "float", name: "radius"}, + {type: "float", name: "size"}, + {type: "int", name: "radSeg"}, + {type: "int", name: "sides"} + ] + }, + { + name: "GenMeshHeightmap", + description: "Generate heightmap mesh from image data", + returnType: "Mesh", + params: [ + {type: "Image", name: "heightmap"}, + {type: "Vector3", name: "size"} + ] + }, + { + name: "GenMeshCubicmap", + description: "Generate cubes-based map mesh from image data", + returnType: "Mesh", + params: [ + {type: "Image", name: "cubicmap"}, + {type: "Vector3", name: "cubeSize"} + ] + }, + { + name: "LoadMaterials", + description: "Load materials from model file", + returnType: "Material *", + params: [ + {type: "const char *", name: "fileName"}, + {type: "int *", name: "materialCount"} + ] + }, + { + name: "LoadMaterialDefault", + description: "Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps)", + returnType: "Material" + }, + { + name: "IsMaterialValid", + description: "Check if material is valid (shader assigned, map textures loaded in GPU)", + returnType: "bool", + params: [ + {type: "Material", name: "material"} + ] + }, + { + name: "UnloadMaterial", + description: "Unload material from GPU memory (VRAM)", + returnType: "void", + params: [ + {type: "Material", name: "material"} + ] + }, + { + name: "SetMaterialTexture", + description: "Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...)", + returnType: "void", + params: [ + {type: "Material *", name: "material"}, + {type: "int", name: "mapType"}, + {type: "Texture2D", name: "texture"} + ] + }, + { + name: "SetModelMeshMaterial", + description: "Set material for a mesh", + returnType: "void", + params: [ + {type: "Model *", name: "model"}, + {type: "int", name: "meshId"}, + {type: "int", name: "materialId"} + ] + }, + { + name: "LoadModelAnimations", + description: "Load model animations from file", + returnType: "ModelAnimation *", + params: [ + {type: "const char *", name: "fileName"}, + {type: "int *", name: "animCount"} + ] + }, + { + name: "UpdateModelAnimation", + description: "Update model animation pose (vertex buffers and bone matrices)", + returnType: "void", + params: [ + {type: "Model", name: "model"}, + {type: "ModelAnimation", name: "anim"}, + {type: "float", name: "frame"} + ] + }, + { + name: "UpdateModelAnimationEx", + description: "Update model animation pose, blending two animations", + returnType: "void", + params: [ + {type: "Model", name: "model"}, + {type: "ModelAnimation", name: "animA"}, + {type: "float", name: "frameA"}, + {type: "ModelAnimation", name: "animB"}, + {type: "float", name: "frameB"}, + {type: "float", name: "blend"} + ] + }, + { + name: "UnloadModelAnimations", + description: "Unload animation array data", + returnType: "void", + params: [ + {type: "ModelAnimation *", name: "animations"}, + {type: "int", name: "animCount"} + ] + }, + { + name: "IsModelAnimationValid", + description: "Check model animation skeleton match", + returnType: "bool", + params: [ + {type: "Model", name: "model"}, + {type: "ModelAnimation", name: "anim"} + ] + }, + { + name: "CheckCollisionSpheres", + description: "Check collision between two spheres", + returnType: "bool", + params: [ + {type: "Vector3", name: "center1"}, + {type: "float", name: "radius1"}, + {type: "Vector3", name: "center2"}, + {type: "float", name: "radius2"} + ] + }, + { + name: "CheckCollisionBoxes", + description: "Check collision between two bounding boxes", + returnType: "bool", + params: [ + {type: "BoundingBox", name: "box1"}, + {type: "BoundingBox", name: "box2"} + ] + }, + { + name: "CheckCollisionBoxSphere", + description: "Check collision between box and sphere", + returnType: "bool", + params: [ + {type: "BoundingBox", name: "box"}, + {type: "Vector3", name: "center"}, + {type: "float", name: "radius"} + ] + }, + { + name: "GetRayCollisionSphere", + description: "Get collision info between ray and sphere", + returnType: "RayCollision", + params: [ + {type: "Ray", name: "ray"}, + {type: "Vector3", name: "center"}, + {type: "float", name: "radius"} + ] + }, + { + name: "GetRayCollisionBox", + description: "Get collision info between ray and box", + returnType: "RayCollision", + params: [ + {type: "Ray", name: "ray"}, + {type: "BoundingBox", name: "box"} + ] + }, + { + name: "GetRayCollisionMesh", + description: "Get collision info between ray and mesh", + returnType: "RayCollision", + params: [ + {type: "Ray", name: "ray"}, + {type: "Mesh", name: "mesh"}, + {type: "Matrix", name: "transform"} + ] + }, + { + name: "GetRayCollisionTriangle", + description: "Get collision info between ray and triangle", + returnType: "RayCollision", + params: [ + {type: "Ray", name: "ray"}, + {type: "Vector3", name: "p1"}, + {type: "Vector3", name: "p2"}, + {type: "Vector3", name: "p3"} + ] + }, + { + name: "GetRayCollisionQuad", + description: "Get collision info between ray and quad", + returnType: "RayCollision", + params: [ + {type: "Ray", name: "ray"}, + {type: "Vector3", name: "p1"}, + {type: "Vector3", name: "p2"}, + {type: "Vector3", name: "p3"}, + {type: "Vector3", name: "p4"} + ] + }, + { + name: "InitAudioDevice", + description: "Initialize audio device and context", + returnType: "void" + }, + { + name: "CloseAudioDevice", + description: "Close the audio device and context", + returnType: "void" + }, + { + name: "IsAudioDeviceReady", + description: "Check if audio device has been initialized successfully", + returnType: "bool" + }, + { + name: "SetMasterVolume", + description: "Set master volume (listener)", + returnType: "void", + params: [ + {type: "float", name: "volume"} + ] + }, + { + name: "GetMasterVolume", + description: "Get master volume (listener)", + returnType: "float" + }, + { + name: "LoadWave", + description: "Load wave data from file", + returnType: "Wave", + params: [ + {type: "const char *", name: "fileName"} + ] + }, + { + name: "LoadWaveFromMemory", + description: "Load wave from memory buffer, fileType refers to extension: i.e. '.wav'", + returnType: "Wave", + params: [ + {type: "const char *", name: "fileType"}, + {type: "const unsigned char *", name: "fileData"}, + {type: "int", name: "dataSize"} + ] + }, + { + name: "IsWaveValid", + description: "Check if wave data is valid (data loaded and parameters)", + returnType: "bool", + params: [ + {type: "Wave", name: "wave"} + ] + }, + { + name: "LoadSound", + description: "Load sound from file", + returnType: "Sound", + params: [ + {type: "const char *", name: "fileName"} + ] + }, + { + name: "LoadSoundFromWave", + description: "Load sound from wave data", + returnType: "Sound", + params: [ + {type: "Wave", name: "wave"} + ] + }, + { + name: "LoadSoundAlias", + description: "Load sound alias, new sound that shares the same sample data as the source sound, does not own the sound data", + returnType: "Sound", + params: [ + {type: "Sound", name: "source"} + ] + }, + { + name: "IsSoundValid", + description: "Check if sound is valid (data loaded and buffers initialized)", + returnType: "bool", + params: [ + {type: "Sound", name: "sound"} + ] + }, + { + name: "UpdateSound", + description: "Update sound buffer with new data (default data format: 32 bit float, stereo)", + returnType: "void", + params: [ + {type: "Sound", name: "sound"}, + {type: "const void *", name: "data"}, + {type: "int", name: "frameCount"} + ] + }, + { + name: "UnloadWave", + description: "Unload wave data", + returnType: "void", + params: [ + {type: "Wave", name: "wave"} + ] + }, + { + name: "UnloadSound", + description: "Unload sound", + returnType: "void", + params: [ + {type: "Sound", name: "sound"} + ] + }, + { + name: "UnloadSoundAlias", + description: "Unload sound alias (does not deallocate sample data)", + returnType: "void", + params: [ + {type: "Sound", name: "alias"} + ] + }, + { + name: "ExportWave", + description: "Export wave data to file, returns true on success", + returnType: "bool", + params: [ + {type: "Wave", name: "wave"}, + {type: "const char *", name: "fileName"} + ] + }, + { + name: "ExportWaveAsCode", + description: "Export wave sample data to code (.h), returns true on success", + returnType: "bool", + params: [ + {type: "Wave", name: "wave"}, + {type: "const char *", name: "fileName"} + ] + }, + { + name: "PlaySound", + description: "Play a sound", + returnType: "void", + params: [ + {type: "Sound", name: "sound"} + ] + }, + { + name: "StopSound", + description: "Stop playing a sound", + returnType: "void", + params: [ + {type: "Sound", name: "sound"} + ] + }, + { + name: "PauseSound", + description: "Pause a sound", + returnType: "void", + params: [ + {type: "Sound", name: "sound"} + ] + }, + { + name: "ResumeSound", + description: "Resume a paused sound", + returnType: "void", + params: [ + {type: "Sound", name: "sound"} + ] + }, + { + name: "IsSoundPlaying", + description: "Check if sound is currently playing", + returnType: "bool", + params: [ + {type: "Sound", name: "sound"} + ] + }, + { + name: "SetSoundVolume", + description: "Set volume for a sound (1.0 is max level)", + returnType: "void", + params: [ + {type: "Sound", name: "sound"}, + {type: "float", name: "volume"} + ] + }, + { + name: "SetSoundPitch", + description: "Set pitch for a sound (1.0 is base level)", + returnType: "void", + params: [ + {type: "Sound", name: "sound"}, + {type: "float", name: "pitch"} + ] + }, + { + name: "SetSoundPan", + description: "Set pan for a sound (-1.0 left, 0.0 center, 1.0 right)", + returnType: "void", + params: [ + {type: "Sound", name: "sound"}, + {type: "float", name: "pan"} + ] + }, + { + name: "WaveCopy", + description: "Copy a wave to a new wave", + returnType: "Wave", + params: [ + {type: "Wave", name: "wave"} + ] + }, + { + name: "WaveCrop", + description: "Crop a wave to defined frames range", + returnType: "void", + params: [ + {type: "Wave *", name: "wave"}, + {type: "int", name: "initFrame"}, + {type: "int", name: "finalFrame"} + ] + }, + { + name: "WaveFormat", + description: "Convert wave data to desired format", + returnType: "void", + params: [ + {type: "Wave *", name: "wave"}, + {type: "int", name: "sampleRate"}, + {type: "int", name: "sampleSize"}, + {type: "int", name: "channels"} + ] + }, + { + name: "LoadWaveSamples", + description: "Load samples data from wave as a 32bit float data array", + returnType: "float *", + params: [ + {type: "Wave", name: "wave"} + ] + }, + { + name: "UnloadWaveSamples", + description: "Unload samples data loaded with LoadWaveSamples()", + returnType: "void", + params: [ + {type: "float *", name: "samples"} + ] + }, + { + name: "LoadMusicStream", + description: "Load music stream from file", + returnType: "Music", + params: [ + {type: "const char *", name: "fileName"} + ] + }, + { + name: "LoadMusicStreamFromMemory", + description: "Load music stream from data", + returnType: "Music", + params: [ + {type: "const char *", name: "fileType"}, + {type: "const unsigned char *", name: "data"}, + {type: "int", name: "dataSize"} + ] + }, + { + name: "IsMusicValid", + description: "Check if music stream is valid (context and buffers initialized)", + returnType: "bool", + params: [ + {type: "Music", name: "music"} + ] + }, + { + name: "UnloadMusicStream", + description: "Unload music stream", + returnType: "void", + params: [ + {type: "Music", name: "music"} + ] + }, + { + name: "PlayMusicStream", + description: "Start music playing", + returnType: "void", + params: [ + {type: "Music", name: "music"} + ] + }, + { + name: "IsMusicStreamPlaying", + description: "Check if music is playing", + returnType: "bool", + params: [ + {type: "Music", name: "music"} + ] + }, + { + name: "UpdateMusicStream", + description: "Update buffers for music streaming", + returnType: "void", + params: [ + {type: "Music", name: "music"} + ] + }, + { + name: "StopMusicStream", + description: "Stop music playing", + returnType: "void", + params: [ + {type: "Music", name: "music"} + ] + }, + { + name: "PauseMusicStream", + description: "Pause music playing", + returnType: "void", + params: [ + {type: "Music", name: "music"} + ] + }, + { + name: "ResumeMusicStream", + description: "Resume playing paused music", + returnType: "void", + params: [ + {type: "Music", name: "music"} + ] + }, + { + name: "SeekMusicStream", + description: "Seek music to a position (in seconds)", + returnType: "void", + params: [ + {type: "Music", name: "music"}, + {type: "float", name: "position"} + ] + }, + { + name: "SetMusicVolume", + description: "Set volume for music (1.0 is max level)", + returnType: "void", + params: [ + {type: "Music", name: "music"}, + {type: "float", name: "volume"} + ] + }, + { + name: "SetMusicPitch", + description: "Set pitch for music (1.0 is base level)", + returnType: "void", + params: [ + {type: "Music", name: "music"}, + {type: "float", name: "pitch"} + ] + }, + { + name: "SetMusicPan", + description: "Set pan for music (-1.0 left, 0.0 center, 1.0 right)", + returnType: "void", + params: [ + {type: "Music", name: "music"}, + {type: "float", name: "pan"} + ] + }, + { + name: "GetMusicTimeLength", + description: "Get music time length (in seconds)", + returnType: "float", + params: [ + {type: "Music", name: "music"} + ] + }, + { + name: "GetMusicTimePlayed", + description: "Get current music time played (in seconds)", + returnType: "float", + params: [ + {type: "Music", name: "music"} + ] + }, + { + name: "LoadAudioStream", + description: "Load audio stream (to stream raw audio pcm data)", + returnType: "AudioStream", + params: [ + {type: "unsigned int", name: "sampleRate"}, + {type: "unsigned int", name: "sampleSize"}, + {type: "unsigned int", name: "channels"} + ] + }, + { + name: "IsAudioStreamValid", + description: "Check if an audio stream is valid (buffers initialized)", + returnType: "bool", + params: [ + {type: "AudioStream", name: "stream"} + ] + }, + { + name: "UnloadAudioStream", + description: "Unload audio stream and free memory", + returnType: "void", + params: [ + {type: "AudioStream", name: "stream"} + ] + }, + { + name: "UpdateAudioStream", + description: "Update audio stream buffers with data", + returnType: "void", + params: [ + {type: "AudioStream", name: "stream"}, + {type: "const void *", name: "data"}, + {type: "int", name: "frameCount"} + ] + }, + { + name: "IsAudioStreamProcessed", + description: "Check if any audio stream buffers requires refill", + returnType: "bool", + params: [ + {type: "AudioStream", name: "stream"} + ] + }, + { + name: "PlayAudioStream", + description: "Play audio stream", + returnType: "void", + params: [ + {type: "AudioStream", name: "stream"} + ] + }, + { + name: "PauseAudioStream", + description: "Pause audio stream", + returnType: "void", + params: [ + {type: "AudioStream", name: "stream"} + ] + }, + { + name: "ResumeAudioStream", + description: "Resume audio stream", + returnType: "void", + params: [ + {type: "AudioStream", name: "stream"} + ] + }, + { + name: "IsAudioStreamPlaying", + description: "Check if audio stream is playing", + returnType: "bool", + params: [ + {type: "AudioStream", name: "stream"} + ] + }, + { + name: "StopAudioStream", + description: "Stop audio stream", + returnType: "void", + params: [ + {type: "AudioStream", name: "stream"} + ] + }, + { + name: "SetAudioStreamVolume", + description: "Set volume for audio stream (1.0 is max level)", + returnType: "void", + params: [ + {type: "AudioStream", name: "stream"}, + {type: "float", name: "volume"} + ] + }, + { + name: "SetAudioStreamPitch", + description: "Set pitch for audio stream (1.0 is base level)", + returnType: "void", + params: [ + {type: "AudioStream", name: "stream"}, + {type: "float", name: "pitch"} + ] + }, + { + name: "SetAudioStreamPan", + description: "Set pan for audio stream (-1.0 left, 0.0 center, 1.0 right)", + returnType: "void", + params: [ + {type: "AudioStream", name: "stream"}, + {type: "float", name: "pan"} + ] + }, + { + name: "SetAudioStreamBufferSizeDefault", + description: "Default size for new audio streams", + returnType: "void", + params: [ + {type: "int", name: "size"} + ] + }, + { + name: "SetAudioStreamCallback", + description: "Audio thread callback to request new data", + returnType: "void", + params: [ + {type: "AudioStream", name: "stream"}, + {type: "AudioCallback", name: "callback"} + ] + }, + { + name: "AttachAudioStreamProcessor", + description: "Attach audio stream processor to stream, receives frames x 2 samples as 'float' (stereo)", + returnType: "void", + params: [ + {type: "AudioStream", name: "stream"}, + {type: "AudioCallback", name: "processor"} + ] + }, + { + name: "DetachAudioStreamProcessor", + description: "Detach audio stream processor from stream", + returnType: "void", + params: [ + {type: "AudioStream", name: "stream"}, + {type: "AudioCallback", name: "processor"} + ] + }, + { + name: "AttachAudioMixedProcessor", + description: "Attach audio stream processor to the entire audio pipeline, receives frames x 2 samples as 'float' (stereo)", + returnType: "void", + params: [ + {type: "AudioCallback", name: "processor"} + ] + }, + { + name: "DetachAudioMixedProcessor", + description: "Detach audio stream processor from the entire audio pipeline", + returnType: "void", + params: [ + {type: "AudioCallback", name: "processor"} + ] + } + ] +}; diff --git a/tools/rlparser/rlparser.c b/tools/rlparser/rlparser.c index dc2afe114..9fd94c564 100644 --- a/tools/rlparser/rlparser.c +++ b/tools/rlparser/rlparser.c @@ -146,7 +146,7 @@ typedef struct FunctionInfo { } FunctionInfo; // Output format for parsed data -typedef enum { DEFAULT = 0, JSON, XML, LUA, CODE } OutputFormat; +typedef enum { DEFAULT = 0, JSON, XML, LUA, JS, CODE } OutputFormat; //---------------------------------------------------------------------------------- // Global Variables Definition @@ -1062,6 +1062,7 @@ int main(int argc, char *argv[]) else if (outputFormat == JSON) printf("\nOutput format: JSON\n\n"); else if (outputFormat == XML) printf("\nOutput format: XML\n\n"); else if (outputFormat == LUA) printf("\nOutput format: LUA\n\n"); + else if (outputFormat == JS) printf("\nOutput format: JS\n\n"); else if (outputFormat == CODE) printf("\nOutput format: CODE\n\n"); ExportParsedData(outFileName, outputFormat); @@ -1098,10 +1099,10 @@ static void ShowCommandLineInfo(void) printf(" -i, --input : Define input header file to parse.\n"); printf(" NOTE: If not specified, defaults to: raylib.h\n\n"); printf(" -o, --output : Define output file and format.\n"); - printf(" Supported extensions: .txt, .json, .xml, .lua, .h\n"); + printf(" Supported extensions: .txt, .json, .xml, .lua, .js, .h\n"); printf(" NOTE: If not specified, defaults to: raylib_api.txt\n\n"); printf(" -f, --format : Define output format for parser data.\n"); - printf(" Supported types: DEFAULT, JSON, XML, LUA, CODE\n\n"); + printf(" Supported types: DEFAULT, JSON, XML, LUA, JS, CODE\n\n"); printf(" -d, --define : Define functions specifiers (i.e. RLAPI for raylib.h, RMAPI for raymath.h, etc.)\n"); printf(" NOTE: If no specifier defined, defaults to: RLAPI\n\n"); printf(" -t, --truncate : Define string to truncate input after (i.e. \"RLGL IMPLEMENTATION\" for rlgl.h)\n"); @@ -1154,6 +1155,7 @@ static void ProcessCommandLine(int argc, char *argv[]) else if (IsTextEqual(argv[i + 1], "JSON\0", 5)) outputFormat = JSON; else if (IsTextEqual(argv[i + 1], "XML\0", 4)) outputFormat = XML; else if (IsTextEqual(argv[i + 1], "LUA\0", 4)) outputFormat = LUA; + else if (IsTextEqual(argv[i + 1], "JS\0", 3)) outputFormat = JS; else if (IsTextEqual(argv[i + 1], "CODE\0", 5)) outputFormat = CODE; } else printf("WARNING: No format parameters provided\n"); @@ -1863,8 +1865,8 @@ static void ExportParsedData(const char *fileName, int format) for (int i = 0; i < defineCount; i++) { fprintf(outFile, " {\n"); - fprintf(outFile, " name = \"%s\",\n", defines[i].name); - fprintf(outFile, " type = \"%s\",\n", StrDefineType(defines[i].type)); + fprintf(outFile, " name: \"%s\",\n", defines[i].name); + fprintf(outFile, " type: \"%s\",\n", StrDefineType(defines[i].type)); if ((defines[i].type == INT) || (defines[i].type == LONG) || (defines[i].type == FLOAT) || @@ -2007,6 +2009,159 @@ static void ExportParsedData(const char *fileName, int format) fprintf(outFile, " }\n"); fprintf(outFile, "}\n"); } break; + case JS: + { + fprintf(outFile, "export default {\n"); + + // Print defines info + fprintf(outFile, " defines: [\n"); + for (int i = 0; i < defineCount; i++) + { + fprintf(outFile, " {\n"); + fprintf(outFile, " name: \"%s\",\n", defines[i].name); + fprintf(outFile, " type: \"%s\",\n", StrDefineType(defines[i].type)); + if ((defines[i].type == INT) || + (defines[i].type == LONG) || + (defines[i].type == FLOAT) || + (defines[i].type == DOUBLE) || + (defines[i].type == STRING)) + { + fprintf(outFile, " value: %s,\n", defines[i].value); + } + else + { + fprintf(outFile, " value: \"%s\",\n", defines[i].value); + } + fprintf(outFile, " description: \"%s\"\n", defines[i].desc); + fprintf(outFile, " }"); + + if (i < defineCount - 1) fprintf(outFile, ",\n"); + else fprintf(outFile, "\n"); + } + fprintf(outFile, " ],\n"); + + // Print structs info + fprintf(outFile, " structs: [\n"); + for (int i = 0; i < structCount; i++) + { + fprintf(outFile, " {\n"); + fprintf(outFile, " name: \"%s\",\n", structs[i].name); + fprintf(outFile, " description: \"%s\",\n", EscapeBackslashes(structs[i].desc)); + fprintf(outFile, " fields: [\n"); + for (int f = 0; f < structs[i].fieldCount; f++) + { + fprintf(outFile, " {\n"); + fprintf(outFile, " type: \"%s\",\n", structs[i].fieldType[f]); + fprintf(outFile, " name: \"%s\",\n", structs[i].fieldName[f]); + fprintf(outFile, " description: \"%s\"\n", EscapeBackslashes(structs[i].fieldDesc[f])); + fprintf(outFile, " }"); + if (f < structs[i].fieldCount - 1) fprintf(outFile, ",\n"); + else fprintf(outFile, "\n"); + } + fprintf(outFile, " ]\n"); + fprintf(outFile, " }"); + if (i < structCount - 1) fprintf(outFile, ",\n"); + else fprintf(outFile, "\n"); + } + fprintf(outFile, " ],\n"); + + // Print aliases info + fprintf(outFile, " aliases: [\n"); + for (int i = 0; i < aliasCount; i++) + { + fprintf(outFile, " {\n"); + fprintf(outFile, " type: \"%s\",\n", aliases[i].type); + fprintf(outFile, " name: \"%s\",\n", aliases[i].name); + fprintf(outFile, " description: \"%s\"\n", aliases[i].desc); + fprintf(outFile, " }"); + + if (i < aliasCount - 1) fprintf(outFile, ",\n"); + else fprintf(outFile, "\n"); + } + fprintf(outFile, " ],\n"); + + // Print enums info + fprintf(outFile, " enums: [\n"); + for (int i = 0; i < enumCount; i++) + { + fprintf(outFile, " {\n"); + fprintf(outFile, " name: \"%s\",\n", enums[i].name); + fprintf(outFile, " description: \"%s\",\n", EscapeBackslashes(enums[i].desc)); + fprintf(outFile, " values: [\n"); + for (int e = 0; e < enums[i].valueCount; e++) + { + fprintf(outFile, " {\n"); + fprintf(outFile, " name: \"%s\",\n", enums[i].valueName[e]); + fprintf(outFile, " value: %i,\n", enums[i].valueInteger[e]); + fprintf(outFile, " description: \"%s\"\n", EscapeBackslashes(enums[i].valueDesc[e])); + fprintf(outFile, " }"); + if (e < enums[i].valueCount - 1) fprintf(outFile, ",\n"); + else fprintf(outFile, "\n"); + } + fprintf(outFile, " ]\n"); + fprintf(outFile, " }"); + if (i < enumCount - 1) fprintf(outFile, ",\n"); + else fprintf(outFile, "\n"); + } + fprintf(outFile, " ],\n"); + + // Print callbacks info + fprintf(outFile, " callbacks: [\n"); + for (int i = 0; i < callbackCount; i++) + { + fprintf(outFile, " {\n"); + fprintf(outFile, " name: \"%s\",\n", callbacks[i].name); + fprintf(outFile, " description: \"%s\",\n", EscapeBackslashes(callbacks[i].desc)); + fprintf(outFile, " returnType: \"%s\"", callbacks[i].retType); + + if (callbacks[i].paramCount == 0) fprintf(outFile, "\n"); + else + { + fprintf(outFile, ",\n params: [\n"); + for (int p = 0; p < callbacks[i].paramCount; p++) + { + fprintf(outFile, " {type: \"%s\", name: \"%s\"}", callbacks[i].paramType[p], callbacks[i].paramName[p]); + if (p < callbacks[i].paramCount - 1) fprintf(outFile, ",\n"); + else fprintf(outFile, "\n"); + } + fprintf(outFile, " ]\n"); + } + fprintf(outFile, " }"); + + if (i < callbackCount - 1) fprintf(outFile, ",\n"); + else fprintf(outFile, "\n"); + } + fprintf(outFile, " ],\n"); + + // Print functions info + fprintf(outFile, " functions: [\n"); + for (int i = 0; i < funcCount; i++) + { + fprintf(outFile, " {\n"); + fprintf(outFile, " name: \"%s\",\n", funcs[i].name); + fprintf(outFile, " description: \"%s\",\n", EscapeBackslashes(funcs[i].desc)); + fprintf(outFile, " returnType: \"%s\"", funcs[i].retType); + + if (funcs[i].paramCount == 0) fprintf(outFile, "\n"); + else + { + fprintf(outFile, ",\n params: [\n"); + for (int p = 0; p < funcs[i].paramCount; p++) + { + fprintf(outFile, " {type: \"%s\", name: \"%s\"}", funcs[i].paramType[p], funcs[i].paramName[p]); + if (p < funcs[i].paramCount - 1) fprintf(outFile, ",\n"); + else fprintf(outFile, "\n"); + } + fprintf(outFile, " ]\n"); + } + fprintf(outFile, " }"); + + if (i < funcCount - 1) fprintf(outFile, ",\n"); + else fprintf(outFile, "\n"); + } + fprintf(outFile, " ]\n"); + fprintf(outFile, "};\n"); + } break; case CODE: default: break; } From 962bbfc6bfbd7a5acd08e21314fcfa161003a589 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 23 Jun 2026 09:24:06 +0200 Subject: [PATCH 10/94] Revert "Implemented JS output format. (#5929)" This reverts commit b00e465debacac39c9a5510acd57a3a459734403. --- tools/rlparser/output/raylib_api.js | 8525 --------------------------- tools/rlparser/rlparser.c | 165 +- 2 files changed, 5 insertions(+), 8685 deletions(-) delete mode 100644 tools/rlparser/output/raylib_api.js diff --git a/tools/rlparser/output/raylib_api.js b/tools/rlparser/output/raylib_api.js deleted file mode 100644 index 90008764f..000000000 --- a/tools/rlparser/output/raylib_api.js +++ /dev/null @@ -1,8525 +0,0 @@ -export default { - defines: [ - { - name: "RAYLIB_H", - type: "GUARD", - value: "", - description: "" - }, - { - name: "RAYLIB_VERSION_MAJOR", - type: "INT", - value: 6, - description: "" - }, - { - name: "RAYLIB_VERSION_MINOR", - type: "INT", - value: 1, - description: "" - }, - { - name: "RAYLIB_VERSION_PATCH", - type: "INT", - value: 0, - description: "" - }, - { - name: "RAYLIB_VERSION", - type: "STRING", - value: "6.1-dev", - description: "" - }, - { - name: "__declspec(x)", - type: "MACRO", - value: "__attribute__((x))", - description: "" - }, - { - name: "RLAPI", - type: "UNKNOWN", - value: "__declspec(dllexport)", - description: "Building the library as a Win32 shared library (.dll)" - }, - { - name: "PI", - type: "FLOAT", - value: 3.14159265358979323846, - description: "" - }, - { - name: "DEG2RAD", - type: "FLOAT_MATH", - value: "(PI/180.0f)", - description: "" - }, - { - name: "RAD2DEG", - type: "FLOAT_MATH", - value: "(180.0f/PI)", - description: "" - }, - { - name: "RL_MALLOC(sz)", - type: "MACRO", - value: "malloc(sz)", - description: "" - }, - { - name: "RL_CALLOC(n,sz)", - type: "MACRO", - value: "calloc(n,sz)", - description: "" - }, - { - name: "RL_REALLOC(ptr,sz)", - type: "MACRO", - value: "realloc(ptr,sz)", - description: "" - }, - { - name: "RL_FREE(ptr)", - type: "MACRO", - value: "free(ptr)", - description: "" - }, - { - name: "CLITERAL(type)", - type: "MACRO", - value: "type", - description: "" - }, - { - name: "RL_COLOR_TYPE", - type: "GUARD", - value: "", - description: "" - }, - { - name: "RL_RECTANGLE_TYPE", - type: "GUARD", - value: "", - description: "" - }, - { - name: "RL_VECTOR2_TYPE", - type: "GUARD", - value: "", - description: "" - }, - { - name: "RL_VECTOR3_TYPE", - type: "GUARD", - value: "", - description: "" - }, - { - name: "RL_VECTOR4_TYPE", - type: "GUARD", - value: "", - description: "" - }, - { - name: "RL_QUATERNION_TYPE", - type: "GUARD", - value: "", - description: "" - }, - { - name: "RL_MATRIX_TYPE", - type: "GUARD", - value: "", - description: "" - }, - { - name: "LIGHTGRAY", - type: "COLOR", - value: "CLITERAL(Color){ 200, 200, 200, 255 }", - description: "Light Gray" - }, - { - name: "GRAY", - type: "COLOR", - value: "CLITERAL(Color){ 130, 130, 130, 255 }", - description: "Gray" - }, - { - name: "DARKGRAY", - type: "COLOR", - value: "CLITERAL(Color){ 80, 80, 80, 255 }", - description: "Dark Gray" - }, - { - name: "YELLOW", - type: "COLOR", - value: "CLITERAL(Color){ 253, 249, 0, 255 }", - description: "Yellow" - }, - { - name: "GOLD", - type: "COLOR", - value: "CLITERAL(Color){ 255, 203, 0, 255 }", - description: "Gold" - }, - { - name: "ORANGE", - type: "COLOR", - value: "CLITERAL(Color){ 255, 161, 0, 255 }", - description: "Orange" - }, - { - name: "PINK", - type: "COLOR", - value: "CLITERAL(Color){ 255, 109, 194, 255 }", - description: "Pink" - }, - { - name: "RED", - type: "COLOR", - value: "CLITERAL(Color){ 230, 41, 55, 255 }", - description: "Red" - }, - { - name: "MAROON", - type: "COLOR", - value: "CLITERAL(Color){ 190, 33, 55, 255 }", - description: "Maroon" - }, - { - name: "GREEN", - type: "COLOR", - value: "CLITERAL(Color){ 0, 228, 48, 255 }", - description: "Green" - }, - { - name: "LIME", - type: "COLOR", - value: "CLITERAL(Color){ 0, 158, 47, 255 }", - description: "Lime" - }, - { - name: "DARKGREEN", - type: "COLOR", - value: "CLITERAL(Color){ 0, 117, 44, 255 }", - description: "Dark Green" - }, - { - name: "SKYBLUE", - type: "COLOR", - value: "CLITERAL(Color){ 102, 191, 255, 255 }", - description: "Sky Blue" - }, - { - name: "BLUE", - type: "COLOR", - value: "CLITERAL(Color){ 0, 121, 241, 255 }", - description: "Blue" - }, - { - name: "DARKBLUE", - type: "COLOR", - value: "CLITERAL(Color){ 0, 82, 172, 255 }", - description: "Dark Blue" - }, - { - name: "PURPLE", - type: "COLOR", - value: "CLITERAL(Color){ 200, 122, 255, 255 }", - description: "Purple" - }, - { - name: "VIOLET", - type: "COLOR", - value: "CLITERAL(Color){ 135, 60, 190, 255 }", - description: "Violet" - }, - { - name: "DARKPURPLE", - type: "COLOR", - value: "CLITERAL(Color){ 112, 31, 126, 255 }", - description: "Dark Purple" - }, - { - name: "BEIGE", - type: "COLOR", - value: "CLITERAL(Color){ 211, 176, 131, 255 }", - description: "Beige" - }, - { - name: "BROWN", - type: "COLOR", - value: "CLITERAL(Color){ 127, 106, 79, 255 }", - description: "Brown" - }, - { - name: "DARKBROWN", - type: "COLOR", - value: "CLITERAL(Color){ 76, 63, 47, 255 }", - description: "Dark Brown" - }, - { - name: "WHITE", - type: "COLOR", - value: "CLITERAL(Color){ 255, 255, 255, 255 }", - description: "White" - }, - { - name: "BLACK", - type: "COLOR", - value: "CLITERAL(Color){ 0, 0, 0, 255 }", - description: "Black" - }, - { - name: "BLANK", - type: "COLOR", - value: "CLITERAL(Color){ 0, 0, 0, 0 }", - description: "Blank (Transparent)" - }, - { - name: "MAGENTA", - type: "COLOR", - value: "CLITERAL(Color){ 255, 0, 255, 255 }", - description: "Magenta" - }, - { - name: "RAYWHITE", - type: "COLOR", - value: "CLITERAL(Color){ 245, 245, 245, 255 }", - description: "My own White (raylib logo)" - }, - { - name: "RL_BOOL_TYPE", - type: "GUARD", - value: "", - description: "" - }, - { - name: "MOUSE_LEFT_BUTTON", - type: "UNKNOWN", - value: "MOUSE_BUTTON_LEFT", - description: "" - }, - { - name: "MOUSE_RIGHT_BUTTON", - type: "UNKNOWN", - value: "MOUSE_BUTTON_RIGHT", - description: "" - }, - { - name: "MOUSE_MIDDLE_BUTTON", - type: "UNKNOWN", - value: "MOUSE_BUTTON_MIDDLE", - description: "" - }, - { - name: "MATERIAL_MAP_DIFFUSE", - type: "UNKNOWN", - value: "MATERIAL_MAP_ALBEDO", - description: "" - }, - { - name: "MATERIAL_MAP_SPECULAR", - type: "UNKNOWN", - value: "MATERIAL_MAP_METALNESS", - description: "" - }, - { - name: "SHADER_LOC_MAP_DIFFUSE", - type: "UNKNOWN", - value: "SHADER_LOC_MAP_ALBEDO", - description: "" - }, - { - name: "SHADER_LOC_MAP_SPECULAR", - type: "UNKNOWN", - value: "SHADER_LOC_MAP_METALNESS", - description: "" - }, - { - name: "GetMouseRay", - type: "UNKNOWN", - value: "GetScreenToWorldRay", - description: "Compatibility hack for previous raylib versions" - } - ], - structs: [ - { - name: "Vector2", - description: "Vector2, 2 components", - fields: [ - { - type: "float", - name: "x", - description: "Vector x component" - }, - { - type: "float", - name: "y", - description: "Vector y component" - } - ] - }, - { - name: "Vector3", - description: "Vector3, 3 components", - fields: [ - { - type: "float", - name: "x", - description: "Vector x component" - }, - { - type: "float", - name: "y", - description: "Vector y component" - }, - { - type: "float", - name: "z", - description: "Vector z component" - } - ] - }, - { - name: "Vector4", - description: "Vector4, 4 components", - fields: [ - { - type: "float", - name: "x", - description: "Vector x component" - }, - { - type: "float", - name: "y", - description: "Vector y component" - }, - { - type: "float", - name: "z", - description: "Vector z component" - }, - { - type: "float", - name: "w", - description: "Vector w component" - } - ] - }, - { - name: "Matrix", - description: "Matrix, 4x4 components, column major, OpenGL style, right-handed", - fields: [ - { - type: "float", - name: "m0", - description: "Matrix first row (4 components)" - }, - { - type: "float", - name: "m4", - description: "Matrix first row (4 components)" - }, - { - type: "float", - name: "m8", - description: "Matrix first row (4 components)" - }, - { - type: "float", - name: "m12", - description: "Matrix first row (4 components)" - }, - { - type: "float", - name: "m1", - description: "Matrix second row (4 components)" - }, - { - type: "float", - name: "m5", - description: "Matrix second row (4 components)" - }, - { - type: "float", - name: "m9", - description: "Matrix second row (4 components)" - }, - { - type: "float", - name: "m13", - description: "Matrix second row (4 components)" - }, - { - type: "float", - name: "m2", - description: "Matrix third row (4 components)" - }, - { - type: "float", - name: "m6", - description: "Matrix third row (4 components)" - }, - { - type: "float", - name: "m10", - description: "Matrix third row (4 components)" - }, - { - type: "float", - name: "m14", - description: "Matrix third row (4 components)" - }, - { - type: "float", - name: "m3", - description: "Matrix fourth row (4 components)" - }, - { - type: "float", - name: "m7", - description: "Matrix fourth row (4 components)" - }, - { - type: "float", - name: "m11", - description: "Matrix fourth row (4 components)" - }, - { - type: "float", - name: "m15", - description: "Matrix fourth row (4 components)" - } - ] - }, - { - name: "Color", - description: "Color, 4 components, R8G8B8A8 (32bit)", - fields: [ - { - type: "unsigned char", - name: "r", - description: "Color red value" - }, - { - type: "unsigned char", - name: "g", - description: "Color green value" - }, - { - type: "unsigned char", - name: "b", - description: "Color blue value" - }, - { - type: "unsigned char", - name: "a", - description: "Color alpha value" - } - ] - }, - { - name: "Rectangle", - description: "Rectangle, 4 components", - fields: [ - { - type: "float", - name: "x", - description: "Rectangle top-left corner position x" - }, - { - type: "float", - name: "y", - description: "Rectangle top-left corner position y" - }, - { - type: "float", - name: "width", - description: "Rectangle width" - }, - { - type: "float", - name: "height", - description: "Rectangle height" - } - ] - }, - { - name: "Image", - description: "Image, pixel data stored in CPU memory (RAM)", - fields: [ - { - type: "void *", - name: "data", - description: "Image raw data" - }, - { - type: "int", - name: "width", - description: "Image base width" - }, - { - type: "int", - name: "height", - description: "Image base height" - }, - { - type: "int", - name: "mipmaps", - description: "Mipmap levels, 1 by default" - }, - { - type: "int", - name: "format", - description: "Data format (PixelFormat type)" - } - ] - }, - { - name: "Texture", - description: "Texture, tex data stored in GPU memory (VRAM)", - fields: [ - { - type: "unsigned int", - name: "id", - description: "OpenGL texture id" - }, - { - type: "int", - name: "width", - description: "Texture base width" - }, - { - type: "int", - name: "height", - description: "Texture base height" - }, - { - type: "int", - name: "mipmaps", - description: "Mipmap levels, 1 by default" - }, - { - type: "int", - name: "format", - description: "Data format (PixelFormat type)" - } - ] - }, - { - name: "RenderTexture", - description: "RenderTexture, fbo for texture rendering", - fields: [ - { - type: "unsigned int", - name: "id", - description: "OpenGL framebuffer object id" - }, - { - type: "Texture", - name: "texture", - description: "Color buffer attachment texture" - }, - { - type: "Texture", - name: "depth", - description: "Depth buffer attachment texture" - } - ] - }, - { - name: "NPatchInfo", - description: "NPatchInfo, n-patch layout info", - fields: [ - { - type: "Rectangle", - name: "source", - description: "Texture source rectangle" - }, - { - type: "int", - name: "left", - description: "Left border offset" - }, - { - type: "int", - name: "top", - description: "Top border offset" - }, - { - type: "int", - name: "right", - description: "Right border offset" - }, - { - type: "int", - name: "bottom", - description: "Bottom border offset" - }, - { - type: "int", - name: "layout", - description: "Layout of the n-patch: 3x3, 1x3 or 3x1" - } - ] - }, - { - name: "GlyphInfo", - description: "GlyphInfo, font characters glyphs info", - fields: [ - { - type: "int", - name: "value", - description: "Character value (Unicode)" - }, - { - type: "int", - name: "offsetX", - description: "Character offset X when drawing" - }, - { - type: "int", - name: "offsetY", - description: "Character offset Y when drawing" - }, - { - type: "int", - name: "advanceX", - description: "Character advance position X" - }, - { - type: "Image", - name: "image", - description: "Character image data" - } - ] - }, - { - name: "Font", - description: "Font, font texture and GlyphInfo array data", - fields: [ - { - type: "int", - name: "baseSize", - description: "Base size (default chars height)" - }, - { - type: "int", - name: "glyphCount", - description: "Number of glyph characters" - }, - { - type: "int", - name: "glyphPadding", - description: "Padding around the glyph characters" - }, - { - type: "Texture2D", - name: "texture", - description: "Texture atlas containing the glyphs" - }, - { - type: "Rectangle *", - name: "recs", - description: "Rectangles in texture for the glyphs" - }, - { - type: "GlyphInfo *", - name: "glyphs", - description: "Glyphs info data" - } - ] - }, - { - name: "Camera3D", - description: "Camera, defines position/orientation in 3d space", - fields: [ - { - type: "Vector3", - name: "position", - description: "Camera position" - }, - { - type: "Vector3", - name: "target", - description: "Camera target it looks-at" - }, - { - type: "Vector3", - name: "up", - description: "Camera up vector (rotation over its axis)" - }, - { - type: "float", - name: "fovy", - description: "Camera field-of-view aperture in Y (degrees) in perspective, used as near plane height in world units in orthographic" - }, - { - type: "int", - name: "projection", - description: "Camera projection: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC" - } - ] - }, - { - name: "Camera2D", - description: "Camera2D, defines position/orientation in 2d space", - fields: [ - { - type: "Vector2", - name: "offset", - description: "Camera offset (screen space offset from window origin)" - }, - { - type: "Vector2", - name: "target", - description: "Camera target (world space target point that is mapped to screen space offset)" - }, - { - type: "float", - name: "rotation", - description: "Camera rotation in degrees (pivots around target)" - }, - { - type: "float", - name: "zoom", - description: "Camera zoom (scaling around target), must not be set to 0, set to 1.0f for no scale" - } - ] - }, - { - name: "Mesh", - description: "Mesh, vertex data and vao/vbo", - fields: [ - { - type: "int", - name: "vertexCount", - description: "Number of vertices stored in arrays" - }, - { - type: "int", - name: "triangleCount", - description: "Number of triangles stored (indexed or not)" - }, - { - type: "float *", - name: "vertices", - description: "Vertex position (XYZ - 3 components per vertex) (shader-location = 0)" - }, - { - type: "float *", - name: "texcoords", - description: "Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)" - }, - { - type: "float *", - name: "texcoords2", - description: "Vertex texture second coordinates (UV - 2 components per vertex) (shader-location = 5)" - }, - { - type: "float *", - name: "normals", - description: "Vertex normals (XYZ - 3 components per vertex) (shader-location = 2)" - }, - { - type: "float *", - name: "tangents", - description: "Vertex tangents (XYZW - 4 components per vertex) (shader-location = 4)" - }, - { - type: "unsigned char *", - name: "colors", - description: "Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)" - }, - { - type: "unsigned short *", - name: "indices", - description: "Vertex indices (in case vertex data comes indexed)" - }, - { - type: "int", - name: "boneCount", - description: "Number of bones (MAX: 256 bones)" - }, - { - type: "unsigned char *", - name: "boneIndices", - description: "Vertex bone indices, up to 4 bones influence by vertex (skinning) (shader-location = 6)" - }, - { - type: "float *", - name: "boneWeights", - description: "Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7)" - }, - { - type: "float *", - name: "animVertices", - description: "Animated vertex positions (after bones transformations)" - }, - { - type: "float *", - name: "animNormals", - description: "Animated normals (after bones transformations)" - }, - { - type: "unsigned int", - name: "vaoId", - description: "OpenGL Vertex Array Object id" - }, - { - type: "unsigned int *", - name: "vboId", - description: "OpenGL Vertex Buffer Objects id (default vertex data)" - } - ] - }, - { - name: "Shader", - description: "Shader", - fields: [ - { - type: "unsigned int", - name: "id", - description: "Shader program id" - }, - { - type: "int *", - name: "locs", - description: "Shader locations array (RL_MAX_SHADER_LOCATIONS)" - } - ] - }, - { - name: "MaterialMap", - description: "MaterialMap", - fields: [ - { - type: "Texture2D", - name: "texture", - description: "Material map texture" - }, - { - type: "Color", - name: "color", - description: "Material map color" - }, - { - type: "float", - name: "value", - description: "Material map value" - } - ] - }, - { - name: "Material", - description: "Material, includes shader and maps", - fields: [ - { - type: "Shader", - name: "shader", - description: "Material shader" - }, - { - type: "MaterialMap *", - name: "maps", - description: "Material maps array (MAX_MATERIAL_MAPS)" - }, - { - type: "float[4]", - name: "params", - description: "Material generic parameters (if required)" - } - ] - }, - { - name: "Transform", - description: "Transform, vertex transformation data", - fields: [ - { - type: "Vector3", - name: "translation", - description: "Translation" - }, - { - type: "Quaternion", - name: "rotation", - description: "Rotation" - }, - { - type: "Vector3", - name: "scale", - description: "Scale" - } - ] - }, - { - name: "BoneInfo", - description: "Bone, skeletal animation bone", - fields: [ - { - type: "char[32]", - name: "name", - description: "Bone name" - }, - { - type: "int", - name: "parent", - description: "Bone parent" - } - ] - }, - { - name: "ModelSkeleton", - description: "Skeleton, animation bones hierarchy", - fields: [ - { - type: "int", - name: "boneCount", - description: "Number of bones" - }, - { - type: "BoneInfo *", - name: "bones", - description: "Bones information (skeleton)" - }, - { - type: "ModelAnimPose", - name: "bindPose", - description: "Bones base transformation (Transform[])" - } - ] - }, - { - name: "Model", - description: "Model, meshes, materials and animation data", - fields: [ - { - type: "Matrix", - name: "transform", - description: "Local transform matrix" - }, - { - type: "int", - name: "meshCount", - description: "Number of meshes" - }, - { - type: "int", - name: "materialCount", - description: "Number of materials" - }, - { - type: "Mesh *", - name: "meshes", - description: "Meshes array" - }, - { - type: "Material *", - name: "materials", - description: "Materials array" - }, - { - type: "int *", - name: "meshMaterial", - description: "Mesh material number" - }, - { - type: "ModelSkeleton", - name: "skeleton", - description: "Skeleton for animation" - }, - { - type: "ModelAnimPose", - name: "currentPose", - description: "Current animation pose (Transform[])" - }, - { - type: "Matrix *", - name: "boneMatrices", - description: "Bones animated transformation matrices" - } - ] - }, - { - name: "ModelAnimation", - description: "ModelAnimation, contains a full animation sequence", - fields: [ - { - type: "char[32]", - name: "name", - description: "Animation name" - }, - { - type: "int", - name: "boneCount", - description: "Number of bones (per pose)" - }, - { - type: "int", - name: "keyframeCount", - description: "Number of animation key frames" - }, - { - type: "ModelAnimPose *", - name: "keyframePoses", - description: "Animation sequence keyframe poses [keyframe][pose]" - } - ] - }, - { - name: "Ray", - description: "Ray, ray for raycasting", - fields: [ - { - type: "Vector3", - name: "position", - description: "Ray position (origin)" - }, - { - type: "Vector3", - name: "direction", - description: "Ray direction (normalized)" - } - ] - }, - { - name: "RayCollision", - description: "RayCollision, ray hit information", - fields: [ - { - type: "bool", - name: "hit", - description: "Did the ray hit something?" - }, - { - type: "float", - name: "distance", - description: "Distance to the nearest hit" - }, - { - type: "Vector3", - name: "point", - description: "Point of the nearest hit" - }, - { - type: "Vector3", - name: "normal", - description: "Surface normal of hit" - } - ] - }, - { - name: "BoundingBox", - description: "BoundingBox", - fields: [ - { - type: "Vector3", - name: "min", - description: "Minimum vertex box-corner" - }, - { - type: "Vector3", - name: "max", - description: "Maximum vertex box-corner" - } - ] - }, - { - name: "Wave", - description: "Wave, audio wave data", - fields: [ - { - type: "unsigned int", - name: "frameCount", - description: "Total number of frames (considering channels)" - }, - { - type: "unsigned int", - name: "sampleRate", - description: "Frequency (samples per second)" - }, - { - type: "unsigned int", - name: "sampleSize", - description: "Bit depth (bits per sample): 8, 16, 32 (24 not supported)" - }, - { - type: "unsigned int", - name: "channels", - description: "Number of channels (1-mono, 2-stereo, ...)" - }, - { - type: "void *", - name: "data", - description: "Buffer data pointer" - } - ] - }, - { - name: "AudioStream", - description: "AudioStream, custom audio stream", - fields: [ - { - type: "rAudioBuffer *", - name: "buffer", - description: "Pointer to internal data used by the audio system" - }, - { - type: "rAudioProcessor *", - name: "processor", - description: "Pointer to internal data processor, useful for audio effects" - }, - { - type: "unsigned int", - name: "sampleRate", - description: "Frequency (samples per second)" - }, - { - type: "unsigned int", - name: "sampleSize", - description: "Bit depth (bits per sample): 8, 16, 32 (24 not supported)" - }, - { - type: "unsigned int", - name: "channels", - description: "Number of channels (1-mono, 2-stereo, ...)" - } - ] - }, - { - name: "Sound", - description: "Sound", - fields: [ - { - type: "AudioStream", - name: "stream", - description: "Audio stream" - }, - { - type: "unsigned int", - name: "frameCount", - description: "Total number of frames (considering channels)" - } - ] - }, - { - name: "Music", - description: "Music, audio stream, anything longer than ~10 seconds should be streamed", - fields: [ - { - type: "AudioStream", - name: "stream", - description: "Audio stream" - }, - { - type: "unsigned int", - name: "frameCount", - description: "Total number of frames (considering channels)" - }, - { - type: "bool", - name: "looping", - description: "Music looping enable" - }, - { - type: "int", - name: "ctxType", - description: "Type of music context (audio filetype)" - }, - { - type: "void *", - name: "ctxData", - description: "Audio context data, depends on type" - } - ] - }, - { - name: "VrDeviceInfo", - description: "VrDeviceInfo, Head-Mounted-Display device parameters", - fields: [ - { - type: "int", - name: "hResolution", - description: "Horizontal resolution in pixels" - }, - { - type: "int", - name: "vResolution", - description: "Vertical resolution in pixels" - }, - { - type: "float", - name: "hScreenSize", - description: "Horizontal size in meters" - }, - { - type: "float", - name: "vScreenSize", - description: "Vertical size in meters" - }, - { - type: "float", - name: "eyeToScreenDistance", - description: "Distance between eye and display in meters" - }, - { - type: "float", - name: "lensSeparationDistance", - description: "Lens separation distance in meters" - }, - { - type: "float", - name: "interpupillaryDistance", - description: "IPD (distance between pupils) in meters" - }, - { - type: "float[4]", - name: "lensDistortionValues", - description: "Lens distortion constant parameters" - }, - { - type: "float[4]", - name: "chromaAbCorrection", - description: "Chromatic aberration correction parameters" - } - ] - }, - { - name: "VrStereoConfig", - description: "VrStereoConfig, VR stereo rendering configuration for simulator", - fields: [ - { - type: "Matrix[2]", - name: "projection", - description: "VR projection matrices (per eye)" - }, - { - type: "Matrix[2]", - name: "viewOffset", - description: "VR view offset matrices (per eye)" - }, - { - type: "float[2]", - name: "leftLensCenter", - description: "VR left lens center" - }, - { - type: "float[2]", - name: "rightLensCenter", - description: "VR right lens center" - }, - { - type: "float[2]", - name: "leftScreenCenter", - description: "VR left screen center" - }, - { - type: "float[2]", - name: "rightScreenCenter", - description: "VR right screen center" - }, - { - type: "float[2]", - name: "scale", - description: "VR distortion scale" - }, - { - type: "float[2]", - name: "scaleIn", - description: "VR distortion scale in" - } - ] - }, - { - name: "FilePathList", - description: "File path list", - fields: [ - { - type: "unsigned int", - name: "count", - description: "Filepaths entries count" - }, - { - type: "char **", - name: "paths", - description: "Filepaths entries" - } - ] - }, - { - name: "AutomationEvent", - description: "Automation event", - fields: [ - { - type: "unsigned int", - name: "frame", - description: "Event frame" - }, - { - type: "unsigned int", - name: "type", - description: "Event type (AutomationEventType)" - }, - { - type: "int[4]", - name: "params", - description: "Event parameters (if required)" - } - ] - }, - { - name: "AutomationEventList", - description: "Automation event list", - fields: [ - { - type: "unsigned int", - name: "capacity", - description: "Events max entries (MAX_AUTOMATION_EVENTS)" - }, - { - type: "unsigned int", - name: "count", - description: "Events entries count" - }, - { - type: "AutomationEvent *", - name: "events", - description: "Events entries" - } - ] - } - ], - aliases: [ - { - type: "Vector4", - name: "Quaternion", - description: "Quaternion, 4 components (Vector4 alias)" - }, - { - type: "Texture", - name: "Texture2D", - description: "Texture2D, same as Texture" - }, - { - type: "Texture", - name: "TextureCubemap", - description: "TextureCubemap, same as Texture" - }, - { - type: "RenderTexture", - name: "RenderTexture2D", - description: "RenderTexture2D, same as RenderTexture" - }, - { - type: "Camera3D", - name: "Camera", - description: "Camera type fallback, defaults to Camera3D" - }, - { - type: "Transform", - name: "*ModelAnimPose", - description: "Anim pose, an array of Transform[]" - } - ], - enums: [ - { - name: "ConfigFlags", - description: "System/Window config flags", - values: [ - { - name: "FLAG_VSYNC_HINT", - value: 64, - description: "Set to try enabling V-Sync on GPU" - }, - { - name: "FLAG_FULLSCREEN_MODE", - value: 2, - description: "Set to run program in fullscreen" - }, - { - name: "FLAG_WINDOW_RESIZABLE", - value: 4, - description: "Set to allow resizable window" - }, - { - name: "FLAG_WINDOW_UNDECORATED", - value: 8, - description: "Set to disable window decoration (frame and buttons)" - }, - { - name: "FLAG_WINDOW_HIDDEN", - value: 128, - description: "Set to hide window" - }, - { - name: "FLAG_WINDOW_MINIMIZED", - value: 512, - description: "Set to minimize window (iconify)" - }, - { - name: "FLAG_WINDOW_MAXIMIZED", - value: 1024, - description: "Set to maximize window (expanded to monitor)" - }, - { - name: "FLAG_WINDOW_UNFOCUSED", - value: 2048, - description: "Set to window non focused" - }, - { - name: "FLAG_WINDOW_TOPMOST", - value: 4096, - description: "Set to window always on top" - }, - { - name: "FLAG_WINDOW_ALWAYS_RUN", - value: 256, - description: "Set to allow windows running while minimized" - }, - { - name: "FLAG_WINDOW_TRANSPARENT", - value: 16, - description: "Set to allow transparent framebuffer" - }, - { - name: "FLAG_WINDOW_HIGHDPI", - value: 8192, - description: "Set to support HighDPI" - }, - { - name: "FLAG_WINDOW_MOUSE_PASSTHROUGH", - value: 16384, - description: "Set to support mouse passthrough, only supported when FLAG_WINDOW_UNDECORATED" - }, - { - name: "FLAG_BORDERLESS_WINDOWED_MODE", - value: 32768, - description: "Set to run program in borderless windowed mode" - }, - { - name: "FLAG_MSAA_4X_HINT", - value: 32, - description: "Set to try enabling MSAA 4X" - }, - { - name: "FLAG_INTERLACED_HINT", - value: 65536, - description: "Set to try enabling interlaced video format (for V3D)" - } - ] - }, - { - name: "TraceLogLevel", - description: "Trace log level", - values: [ - { - name: "LOG_ALL", - value: 0, - description: "Display all logs" - }, - { - name: "LOG_TRACE", - value: 1, - description: "Trace logging, intended for internal use only" - }, - { - name: "LOG_DEBUG", - value: 2, - description: "Debug logging, used for internal debugging, it should be disabled on release builds" - }, - { - name: "LOG_INFO", - value: 3, - description: "Info logging, used for program execution info" - }, - { - name: "LOG_WARNING", - value: 4, - description: "Warning logging, used on recoverable failures" - }, - { - name: "LOG_ERROR", - value: 5, - description: "Error logging, used on unrecoverable failures" - }, - { - name: "LOG_FATAL", - value: 6, - description: "Fatal logging, used to abort program: exit(EXIT_FAILURE)" - }, - { - name: "LOG_NONE", - value: 7, - description: "Disable logging" - } - ] - }, - { - name: "KeyboardKey", - description: "Keyboard keys (US keyboard layout)", - values: [ - { - name: "KEY_NULL", - value: 0, - description: "Key: NULL, used for no key pressed" - }, - { - name: "KEY_APOSTROPHE", - value: 39, - description: "Key: '" - }, - { - name: "KEY_COMMA", - value: 44, - description: "Key: ," - }, - { - name: "KEY_MINUS", - value: 45, - description: "Key: -" - }, - { - name: "KEY_PERIOD", - value: 46, - description: "Key: ." - }, - { - name: "KEY_SLASH", - value: 47, - description: "Key: /" - }, - { - name: "KEY_ZERO", - value: 48, - description: "Key: 0" - }, - { - name: "KEY_ONE", - value: 49, - description: "Key: 1" - }, - { - name: "KEY_TWO", - value: 50, - description: "Key: 2" - }, - { - name: "KEY_THREE", - value: 51, - description: "Key: 3" - }, - { - name: "KEY_FOUR", - value: 52, - description: "Key: 4" - }, - { - name: "KEY_FIVE", - value: 53, - description: "Key: 5" - }, - { - name: "KEY_SIX", - value: 54, - description: "Key: 6" - }, - { - name: "KEY_SEVEN", - value: 55, - description: "Key: 7" - }, - { - name: "KEY_EIGHT", - value: 56, - description: "Key: 8" - }, - { - name: "KEY_NINE", - value: 57, - description: "Key: 9" - }, - { - name: "KEY_SEMICOLON", - value: 59, - description: "Key: ;" - }, - { - name: "KEY_EQUAL", - value: 61, - description: "Key: =" - }, - { - name: "KEY_A", - value: 65, - description: "Key: A | a" - }, - { - name: "KEY_B", - value: 66, - description: "Key: B | b" - }, - { - name: "KEY_C", - value: 67, - description: "Key: C | c" - }, - { - name: "KEY_D", - value: 68, - description: "Key: D | d" - }, - { - name: "KEY_E", - value: 69, - description: "Key: E | e" - }, - { - name: "KEY_F", - value: 70, - description: "Key: F | f" - }, - { - name: "KEY_G", - value: 71, - description: "Key: G | g" - }, - { - name: "KEY_H", - value: 72, - description: "Key: H | h" - }, - { - name: "KEY_I", - value: 73, - description: "Key: I | i" - }, - { - name: "KEY_J", - value: 74, - description: "Key: J | j" - }, - { - name: "KEY_K", - value: 75, - description: "Key: K | k" - }, - { - name: "KEY_L", - value: 76, - description: "Key: L | l" - }, - { - name: "KEY_M", - value: 77, - description: "Key: M | m" - }, - { - name: "KEY_N", - value: 78, - description: "Key: N | n" - }, - { - name: "KEY_O", - value: 79, - description: "Key: O | o" - }, - { - name: "KEY_P", - value: 80, - description: "Key: P | p" - }, - { - name: "KEY_Q", - value: 81, - description: "Key: Q | q" - }, - { - name: "KEY_R", - value: 82, - description: "Key: R | r" - }, - { - name: "KEY_S", - value: 83, - description: "Key: S | s" - }, - { - name: "KEY_T", - value: 84, - description: "Key: T | t" - }, - { - name: "KEY_U", - value: 85, - description: "Key: U | u" - }, - { - name: "KEY_V", - value: 86, - description: "Key: V | v" - }, - { - name: "KEY_W", - value: 87, - description: "Key: W | w" - }, - { - name: "KEY_X", - value: 88, - description: "Key: X | x" - }, - { - name: "KEY_Y", - value: 89, - description: "Key: Y | y" - }, - { - name: "KEY_Z", - value: 90, - description: "Key: Z | z" - }, - { - name: "KEY_LEFT_BRACKET", - value: 91, - description: "Key: [" - }, - { - name: "KEY_BACKSLASH", - value: 92, - description: "Key: '\\'" - }, - { - name: "KEY_RIGHT_BRACKET", - value: 93, - description: "Key: ]" - }, - { - name: "KEY_GRAVE", - value: 96, - description: "Key: `" - }, - { - name: "KEY_SPACE", - value: 32, - description: "Key: Space" - }, - { - name: "KEY_ESCAPE", - value: 256, - description: "Key: Esc" - }, - { - name: "KEY_ENTER", - value: 257, - description: "Key: Enter" - }, - { - name: "KEY_TAB", - value: 258, - description: "Key: Tab" - }, - { - name: "KEY_BACKSPACE", - value: 259, - description: "Key: Backspace" - }, - { - name: "KEY_INSERT", - value: 260, - description: "Key: Ins" - }, - { - name: "KEY_DELETE", - value: 261, - description: "Key: Del" - }, - { - name: "KEY_RIGHT", - value: 262, - description: "Key: Cursor right" - }, - { - name: "KEY_LEFT", - value: 263, - description: "Key: Cursor left" - }, - { - name: "KEY_DOWN", - value: 264, - description: "Key: Cursor down" - }, - { - name: "KEY_UP", - value: 265, - description: "Key: Cursor up" - }, - { - name: "KEY_PAGE_UP", - value: 266, - description: "Key: Page up" - }, - { - name: "KEY_PAGE_DOWN", - value: 267, - description: "Key: Page down" - }, - { - name: "KEY_HOME", - value: 268, - description: "Key: Home" - }, - { - name: "KEY_END", - value: 269, - description: "Key: End" - }, - { - name: "KEY_CAPS_LOCK", - value: 280, - description: "Key: Caps lock" - }, - { - name: "KEY_SCROLL_LOCK", - value: 281, - description: "Key: Scroll down" - }, - { - name: "KEY_NUM_LOCK", - value: 282, - description: "Key: Num lock" - }, - { - name: "KEY_PRINT_SCREEN", - value: 283, - description: "Key: Print screen" - }, - { - name: "KEY_PAUSE", - value: 284, - description: "Key: Pause" - }, - { - name: "KEY_F1", - value: 290, - description: "Key: F1" - }, - { - name: "KEY_F2", - value: 291, - description: "Key: F2" - }, - { - name: "KEY_F3", - value: 292, - description: "Key: F3" - }, - { - name: "KEY_F4", - value: 293, - description: "Key: F4" - }, - { - name: "KEY_F5", - value: 294, - description: "Key: F5" - }, - { - name: "KEY_F6", - value: 295, - description: "Key: F6" - }, - { - name: "KEY_F7", - value: 296, - description: "Key: F7" - }, - { - name: "KEY_F8", - value: 297, - description: "Key: F8" - }, - { - name: "KEY_F9", - value: 298, - description: "Key: F9" - }, - { - name: "KEY_F10", - value: 299, - description: "Key: F10" - }, - { - name: "KEY_F11", - value: 300, - description: "Key: F11" - }, - { - name: "KEY_F12", - value: 301, - description: "Key: F12" - }, - { - name: "KEY_LEFT_SHIFT", - value: 340, - description: "Key: Shift left" - }, - { - name: "KEY_LEFT_CONTROL", - value: 341, - description: "Key: Control left" - }, - { - name: "KEY_LEFT_ALT", - value: 342, - description: "Key: Alt left" - }, - { - name: "KEY_LEFT_SUPER", - value: 343, - description: "Key: Super left" - }, - { - name: "KEY_RIGHT_SHIFT", - value: 344, - description: "Key: Shift right" - }, - { - name: "KEY_RIGHT_CONTROL", - value: 345, - description: "Key: Control right" - }, - { - name: "KEY_RIGHT_ALT", - value: 346, - description: "Key: Alt right" - }, - { - name: "KEY_RIGHT_SUPER", - value: 347, - description: "Key: Super right" - }, - { - name: "KEY_KB_MENU", - value: 348, - description: "Key: KB menu" - }, - { - name: "KEY_KP_0", - value: 320, - description: "Key: Keypad 0" - }, - { - name: "KEY_KP_1", - value: 321, - description: "Key: Keypad 1" - }, - { - name: "KEY_KP_2", - value: 322, - description: "Key: Keypad 2" - }, - { - name: "KEY_KP_3", - value: 323, - description: "Key: Keypad 3" - }, - { - name: "KEY_KP_4", - value: 324, - description: "Key: Keypad 4" - }, - { - name: "KEY_KP_5", - value: 325, - description: "Key: Keypad 5" - }, - { - name: "KEY_KP_6", - value: 326, - description: "Key: Keypad 6" - }, - { - name: "KEY_KP_7", - value: 327, - description: "Key: Keypad 7" - }, - { - name: "KEY_KP_8", - value: 328, - description: "Key: Keypad 8" - }, - { - name: "KEY_KP_9", - value: 329, - description: "Key: Keypad 9" - }, - { - name: "KEY_KP_DECIMAL", - value: 330, - description: "Key: Keypad ." - }, - { - name: "KEY_KP_DIVIDE", - value: 331, - description: "Key: Keypad /" - }, - { - name: "KEY_KP_MULTIPLY", - value: 332, - description: "Key: Keypad *" - }, - { - name: "KEY_KP_SUBTRACT", - value: 333, - description: "Key: Keypad -" - }, - { - name: "KEY_KP_ADD", - value: 334, - description: "Key: Keypad +" - }, - { - name: "KEY_KP_ENTER", - value: 335, - description: "Key: Keypad Enter" - }, - { - name: "KEY_KP_EQUAL", - value: 336, - description: "Key: Keypad =" - }, - { - name: "KEY_BACK", - value: 4, - description: "Key: Android back button" - }, - { - name: "KEY_MENU", - value: 5, - description: "Key: Android menu button" - }, - { - name: "KEY_VOLUME_UP", - value: 24, - description: "Key: Android volume up button" - }, - { - name: "KEY_VOLUME_DOWN", - value: 25, - description: "Key: Android volume down button" - } - ] - }, - { - name: "MouseButton", - description: "Mouse buttons", - values: [ - { - name: "MOUSE_BUTTON_LEFT", - value: 0, - description: "Mouse button left" - }, - { - name: "MOUSE_BUTTON_RIGHT", - value: 1, - description: "Mouse button right" - }, - { - name: "MOUSE_BUTTON_MIDDLE", - value: 2, - description: "Mouse button middle (pressed wheel)" - }, - { - name: "MOUSE_BUTTON_SIDE", - value: 3, - description: "Mouse button side (advanced mouse device)" - }, - { - name: "MOUSE_BUTTON_EXTRA", - value: 4, - description: "Mouse button extra (advanced mouse device)" - }, - { - name: "MOUSE_BUTTON_FORWARD", - value: 5, - description: "Mouse button forward (advanced mouse device)" - }, - { - name: "MOUSE_BUTTON_BACK", - value: 6, - description: "Mouse button back (advanced mouse device)" - } - ] - }, - { - name: "MouseCursor", - description: "Mouse cursor", - values: [ - { - name: "MOUSE_CURSOR_DEFAULT", - value: 0, - description: "Default pointer shape" - }, - { - name: "MOUSE_CURSOR_ARROW", - value: 1, - description: "Arrow shape" - }, - { - name: "MOUSE_CURSOR_IBEAM", - value: 2, - description: "Text writing cursor shape" - }, - { - name: "MOUSE_CURSOR_CROSSHAIR", - value: 3, - description: "Cross shape" - }, - { - name: "MOUSE_CURSOR_POINTING_HAND", - value: 4, - description: "Pointing hand cursor" - }, - { - name: "MOUSE_CURSOR_RESIZE_EW", - value: 5, - description: "Horizontal resize/move arrow shape" - }, - { - name: "MOUSE_CURSOR_RESIZE_NS", - value: 6, - description: "Vertical resize/move arrow shape" - }, - { - name: "MOUSE_CURSOR_RESIZE_NWSE", - value: 7, - description: "Top-left to bottom-right diagonal resize/move arrow shape" - }, - { - name: "MOUSE_CURSOR_RESIZE_NESW", - value: 8, - description: "The top-right to bottom-left diagonal resize/move arrow shape" - }, - { - name: "MOUSE_CURSOR_RESIZE_ALL", - value: 9, - description: "The omnidirectional resize/move cursor shape" - }, - { - name: "MOUSE_CURSOR_NOT_ALLOWED", - value: 10, - description: "The operation-not-allowed shape" - } - ] - }, - { - name: "GamepadButton", - description: "Gamepad buttons", - values: [ - { - name: "GAMEPAD_BUTTON_UNKNOWN", - value: 0, - description: "Unknown button, for error checking" - }, - { - name: "GAMEPAD_BUTTON_LEFT_FACE_UP", - value: 1, - description: "Gamepad left DPAD up button" - }, - { - name: "GAMEPAD_BUTTON_LEFT_FACE_RIGHT", - value: 2, - description: "Gamepad left DPAD right button" - }, - { - name: "GAMEPAD_BUTTON_LEFT_FACE_DOWN", - value: 3, - description: "Gamepad left DPAD down button" - }, - { - name: "GAMEPAD_BUTTON_LEFT_FACE_LEFT", - value: 4, - description: "Gamepad left DPAD left button" - }, - { - name: "GAMEPAD_BUTTON_RIGHT_FACE_UP", - value: 5, - description: "Gamepad right button up (i.e. PS3: Triangle, Xbox: Y)" - }, - { - name: "GAMEPAD_BUTTON_RIGHT_FACE_RIGHT", - value: 6, - description: "Gamepad right button right (i.e. PS3: Circle, Xbox: B)" - }, - { - name: "GAMEPAD_BUTTON_RIGHT_FACE_DOWN", - value: 7, - description: "Gamepad right button down (i.e. PS3: Cross, Xbox: A)" - }, - { - name: "GAMEPAD_BUTTON_RIGHT_FACE_LEFT", - value: 8, - description: "Gamepad right button left (i.e. PS3: Square, Xbox: X)" - }, - { - name: "GAMEPAD_BUTTON_LEFT_TRIGGER_1", - value: 9, - description: "Gamepad top/back trigger left (first), it could be a trailing button" - }, - { - name: "GAMEPAD_BUTTON_LEFT_TRIGGER_2", - value: 10, - description: "Gamepad top/back trigger left (second), it could be a trailing button" - }, - { - name: "GAMEPAD_BUTTON_RIGHT_TRIGGER_1", - value: 11, - description: "Gamepad top/back trigger right (first), it could be a trailing button" - }, - { - name: "GAMEPAD_BUTTON_RIGHT_TRIGGER_2", - value: 12, - description: "Gamepad top/back trigger right (second), it could be a trailing button" - }, - { - name: "GAMEPAD_BUTTON_MIDDLE_LEFT", - value: 13, - description: "Gamepad center buttons, left one (i.e. PS3: Select)" - }, - { - name: "GAMEPAD_BUTTON_MIDDLE", - value: 14, - description: "Gamepad center buttons, middle one (i.e. PS3: PS, Xbox: XBOX)" - }, - { - name: "GAMEPAD_BUTTON_MIDDLE_RIGHT", - value: 15, - description: "Gamepad center buttons, right one (i.e. PS3: Start)" - }, - { - name: "GAMEPAD_BUTTON_LEFT_THUMB", - value: 16, - description: "Gamepad joystick pressed button left" - }, - { - name: "GAMEPAD_BUTTON_RIGHT_THUMB", - value: 17, - description: "Gamepad joystick pressed button right" - } - ] - }, - { - name: "GamepadAxis", - description: "Gamepad axes", - values: [ - { - name: "GAMEPAD_AXIS_LEFT_X", - value: 0, - description: "Gamepad left stick X axis" - }, - { - name: "GAMEPAD_AXIS_LEFT_Y", - value: 1, - description: "Gamepad left stick Y axis" - }, - { - name: "GAMEPAD_AXIS_RIGHT_X", - value: 2, - description: "Gamepad right stick X axis" - }, - { - name: "GAMEPAD_AXIS_RIGHT_Y", - value: 3, - description: "Gamepad right stick Y axis" - }, - { - name: "GAMEPAD_AXIS_LEFT_TRIGGER", - value: 4, - description: "Gamepad back trigger left, pressure level: [1..-1]" - }, - { - name: "GAMEPAD_AXIS_RIGHT_TRIGGER", - value: 5, - description: "Gamepad back trigger right, pressure level: [1..-1]" - } - ] - }, - { - name: "MaterialMapIndex", - description: "Material map index", - values: [ - { - name: "MATERIAL_MAP_ALBEDO", - value: 0, - description: "Albedo material (same as: MATERIAL_MAP_DIFFUSE)" - }, - { - name: "MATERIAL_MAP_METALNESS", - value: 1, - description: "Metalness material (same as: MATERIAL_MAP_SPECULAR)" - }, - { - name: "MATERIAL_MAP_NORMAL", - value: 2, - description: "Normal material" - }, - { - name: "MATERIAL_MAP_ROUGHNESS", - value: 3, - description: "Roughness material" - }, - { - name: "MATERIAL_MAP_OCCLUSION", - value: 4, - description: "Ambient occlusion material" - }, - { - name: "MATERIAL_MAP_EMISSION", - value: 5, - description: "Emission material" - }, - { - name: "MATERIAL_MAP_HEIGHT", - value: 6, - description: "Heightmap material" - }, - { - name: "MATERIAL_MAP_CUBEMAP", - value: 7, - description: "Cubemap material (NOTE: Uses GL_TEXTURE_CUBE_MAP)" - }, - { - name: "MATERIAL_MAP_IRRADIANCE", - value: 8, - description: "Irradiance material (NOTE: Uses GL_TEXTURE_CUBE_MAP)" - }, - { - name: "MATERIAL_MAP_PREFILTER", - value: 9, - description: "Prefilter material (NOTE: Uses GL_TEXTURE_CUBE_MAP)" - }, - { - name: "MATERIAL_MAP_BRDF", - value: 10, - description: "Brdf material" - } - ] - }, - { - name: "ShaderLocationIndex", - description: "Shader location index", - values: [ - { - name: "SHADER_LOC_VERTEX_POSITION", - value: 0, - description: "Shader location: vertex attribute: position" - }, - { - name: "SHADER_LOC_VERTEX_TEXCOORD01", - value: 1, - description: "Shader location: vertex attribute: texcoord01" - }, - { - name: "SHADER_LOC_VERTEX_TEXCOORD02", - value: 2, - description: "Shader location: vertex attribute: texcoord02" - }, - { - name: "SHADER_LOC_VERTEX_NORMAL", - value: 3, - description: "Shader location: vertex attribute: normal" - }, - { - name: "SHADER_LOC_VERTEX_TANGENT", - value: 4, - description: "Shader location: vertex attribute: tangent" - }, - { - name: "SHADER_LOC_VERTEX_COLOR", - value: 5, - description: "Shader location: vertex attribute: color" - }, - { - name: "SHADER_LOC_MATRIX_MVP", - value: 6, - description: "Shader location: matrix uniform: model-view-projection" - }, - { - name: "SHADER_LOC_MATRIX_VIEW", - value: 7, - description: "Shader location: matrix uniform: view (camera transform)" - }, - { - name: "SHADER_LOC_MATRIX_PROJECTION", - value: 8, - description: "Shader location: matrix uniform: projection" - }, - { - name: "SHADER_LOC_MATRIX_MODEL", - value: 9, - description: "Shader location: matrix uniform: model (transform)" - }, - { - name: "SHADER_LOC_MATRIX_NORMAL", - value: 10, - description: "Shader location: matrix uniform: normal" - }, - { - name: "SHADER_LOC_VECTOR_VIEW", - value: 11, - description: "Shader location: vector uniform: view" - }, - { - name: "SHADER_LOC_COLOR_DIFFUSE", - value: 12, - description: "Shader location: vector uniform: diffuse color" - }, - { - name: "SHADER_LOC_COLOR_SPECULAR", - value: 13, - description: "Shader location: vector uniform: specular color" - }, - { - name: "SHADER_LOC_COLOR_AMBIENT", - value: 14, - description: "Shader location: vector uniform: ambient color" - }, - { - name: "SHADER_LOC_MAP_ALBEDO", - value: 15, - description: "Shader location: sampler2d texture: albedo (same as: SHADER_LOC_MAP_DIFFUSE)" - }, - { - name: "SHADER_LOC_MAP_METALNESS", - value: 16, - description: "Shader location: sampler2d texture: metalness (same as: SHADER_LOC_MAP_SPECULAR)" - }, - { - name: "SHADER_LOC_MAP_NORMAL", - value: 17, - description: "Shader location: sampler2d texture: normal" - }, - { - name: "SHADER_LOC_MAP_ROUGHNESS", - value: 18, - description: "Shader location: sampler2d texture: roughness" - }, - { - name: "SHADER_LOC_MAP_OCCLUSION", - value: 19, - description: "Shader location: sampler2d texture: occlusion" - }, - { - name: "SHADER_LOC_MAP_EMISSION", - value: 20, - description: "Shader location: sampler2d texture: emission" - }, - { - name: "SHADER_LOC_MAP_HEIGHT", - value: 21, - description: "Shader location: sampler2d texture: heightmap" - }, - { - name: "SHADER_LOC_MAP_CUBEMAP", - value: 22, - description: "Shader location: samplerCube texture: cubemap" - }, - { - name: "SHADER_LOC_MAP_IRRADIANCE", - value: 23, - description: "Shader location: samplerCube texture: irradiance" - }, - { - name: "SHADER_LOC_MAP_PREFILTER", - value: 24, - description: "Shader location: samplerCube texture: prefilter" - }, - { - name: "SHADER_LOC_MAP_BRDF", - value: 25, - description: "Shader location: sampler2d texture: brdf" - }, - { - name: "SHADER_LOC_VERTEX_BONEIDS", - value: 26, - description: "Shader location: vertex attribute: bone indices" - }, - { - name: "SHADER_LOC_VERTEX_BONEWEIGHTS", - value: 27, - description: "Shader location: vertex attribute: bone weights" - }, - { - name: "SHADER_LOC_MATRIX_BONETRANSFORMS", - value: 28, - description: "Shader location: matrix attribute: bone transforms (animation)" - }, - { - name: "SHADER_LOC_VERTEX_INSTANCETRANSFORM", - value: 29, - description: "Shader location: vertex attribute: instance transforms" - } - ] - }, - { - name: "ShaderUniformDataType", - description: "Shader uniform data type", - values: [ - { - name: "SHADER_UNIFORM_FLOAT", - value: 0, - description: "Shader uniform type: float" - }, - { - name: "SHADER_UNIFORM_VEC2", - value: 1, - description: "Shader uniform type: vec2 (2 float)" - }, - { - name: "SHADER_UNIFORM_VEC3", - value: 2, - description: "Shader uniform type: vec3 (3 float)" - }, - { - name: "SHADER_UNIFORM_VEC4", - value: 3, - description: "Shader uniform type: vec4 (4 float)" - }, - { - name: "SHADER_UNIFORM_INT", - value: 4, - description: "Shader uniform type: int" - }, - { - name: "SHADER_UNIFORM_IVEC2", - value: 5, - description: "Shader uniform type: ivec2 (2 int)" - }, - { - name: "SHADER_UNIFORM_IVEC3", - value: 6, - description: "Shader uniform type: ivec3 (3 int)" - }, - { - name: "SHADER_UNIFORM_IVEC4", - value: 7, - description: "Shader uniform type: ivec4 (4 int)" - }, - { - name: "SHADER_UNIFORM_UINT", - value: 8, - description: "Shader uniform type: unsigned int" - }, - { - name: "SHADER_UNIFORM_UIVEC2", - value: 9, - description: "Shader uniform type: uivec2 (2 unsigned int)" - }, - { - name: "SHADER_UNIFORM_UIVEC3", - value: 10, - description: "Shader uniform type: uivec3 (3 unsigned int)" - }, - { - name: "SHADER_UNIFORM_UIVEC4", - value: 11, - description: "Shader uniform type: uivec4 (4 unsigned int)" - }, - { - name: "SHADER_UNIFORM_SAMPLER2D", - value: 12, - description: "Shader uniform type: sampler2d" - } - ] - }, - { - name: "ShaderAttributeDataType", - description: "Shader attribute data types", - values: [ - { - name: "SHADER_ATTRIB_FLOAT", - value: 0, - description: "Shader attribute type: float" - }, - { - name: "SHADER_ATTRIB_VEC2", - value: 1, - description: "Shader attribute type: vec2 (2 float)" - }, - { - name: "SHADER_ATTRIB_VEC3", - value: 2, - description: "Shader attribute type: vec3 (3 float)" - }, - { - name: "SHADER_ATTRIB_VEC4", - value: 3, - description: "Shader attribute type: vec4 (4 float)" - } - ] - }, - { - name: "PixelFormat", - description: "Pixel formats", - values: [ - { - name: "PIXELFORMAT_UNCOMPRESSED_GRAYSCALE", - value: 1, - description: "8 bit per pixel (no alpha)" - }, - { - name: "PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA", - value: 2, - description: "8*2 bpp (2 channels)" - }, - { - name: "PIXELFORMAT_UNCOMPRESSED_R5G6B5", - value: 3, - description: "16 bpp" - }, - { - name: "PIXELFORMAT_UNCOMPRESSED_R8G8B8", - value: 4, - description: "24 bpp" - }, - { - name: "PIXELFORMAT_UNCOMPRESSED_R5G5B5A1", - value: 5, - description: "16 bpp (1 bit alpha)" - }, - { - name: "PIXELFORMAT_UNCOMPRESSED_R4G4B4A4", - value: 6, - description: "16 bpp (4 bit alpha)" - }, - { - name: "PIXELFORMAT_UNCOMPRESSED_R8G8B8A8", - value: 7, - description: "32 bpp" - }, - { - name: "PIXELFORMAT_UNCOMPRESSED_R32", - value: 8, - description: "32 bpp (1 channel - float)" - }, - { - name: "PIXELFORMAT_UNCOMPRESSED_R32G32B32", - value: 9, - description: "32*3 bpp (3 channels - float)" - }, - { - name: "PIXELFORMAT_UNCOMPRESSED_R32G32B32A32", - value: 10, - description: "32*4 bpp (4 channels - float)" - }, - { - name: "PIXELFORMAT_UNCOMPRESSED_R16", - value: 11, - description: "16 bpp (1 channel - half float)" - }, - { - name: "PIXELFORMAT_UNCOMPRESSED_R16G16B16", - value: 12, - description: "16*3 bpp (3 channels - half float)" - }, - { - name: "PIXELFORMAT_UNCOMPRESSED_R16G16B16A16", - value: 13, - description: "16*4 bpp (4 channels - half float)" - }, - { - name: "PIXELFORMAT_COMPRESSED_DXT1_RGB", - value: 14, - description: "4 bpp (no alpha)" - }, - { - name: "PIXELFORMAT_COMPRESSED_DXT1_RGBA", - value: 15, - description: "4 bpp (1 bit alpha)" - }, - { - name: "PIXELFORMAT_COMPRESSED_DXT3_RGBA", - value: 16, - description: "8 bpp" - }, - { - name: "PIXELFORMAT_COMPRESSED_DXT5_RGBA", - value: 17, - description: "8 bpp" - }, - { - name: "PIXELFORMAT_COMPRESSED_ETC1_RGB", - value: 18, - description: "4 bpp" - }, - { - name: "PIXELFORMAT_COMPRESSED_ETC2_RGB", - value: 19, - description: "4 bpp" - }, - { - name: "PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA", - value: 20, - description: "8 bpp" - }, - { - name: "PIXELFORMAT_COMPRESSED_PVRT_RGB", - value: 21, - description: "4 bpp" - }, - { - name: "PIXELFORMAT_COMPRESSED_PVRT_RGBA", - value: 22, - description: "4 bpp" - }, - { - name: "PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA", - value: 23, - description: "8 bpp" - }, - { - name: "PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA", - value: 24, - description: "2 bpp" - } - ] - }, - { - name: "TextureFilter", - description: "Texture parameters: filter mode", - values: [ - { - name: "TEXTURE_FILTER_POINT", - value: 0, - description: "No filter, pixel approximation" - }, - { - name: "TEXTURE_FILTER_BILINEAR", - value: 1, - description: "Linear filtering" - }, - { - name: "TEXTURE_FILTER_TRILINEAR", - value: 2, - description: "Trilinear filtering (linear with mipmaps)" - }, - { - name: "TEXTURE_FILTER_ANISOTROPIC_4X", - value: 3, - description: "Anisotropic filtering 4x" - }, - { - name: "TEXTURE_FILTER_ANISOTROPIC_8X", - value: 4, - description: "Anisotropic filtering 8x" - }, - { - name: "TEXTURE_FILTER_ANISOTROPIC_16X", - value: 5, - description: "Anisotropic filtering 16x" - } - ] - }, - { - name: "TextureWrap", - description: "Texture parameters: wrap mode", - values: [ - { - name: "TEXTURE_WRAP_REPEAT", - value: 0, - description: "Repeats texture in tiled mode" - }, - { - name: "TEXTURE_WRAP_CLAMP", - value: 1, - description: "Clamps texture to edge pixel in tiled mode" - }, - { - name: "TEXTURE_WRAP_MIRROR_REPEAT", - value: 2, - description: "Mirrors and repeats the texture in tiled mode" - }, - { - name: "TEXTURE_WRAP_MIRROR_CLAMP", - value: 3, - description: "Mirrors and clamps to border the texture in tiled mode" - } - ] - }, - { - name: "CubemapLayout", - description: "Cubemap layouts", - values: [ - { - name: "CUBEMAP_LAYOUT_AUTO_DETECT", - value: 0, - description: "Automatically detect layout type" - }, - { - name: "CUBEMAP_LAYOUT_LINE_VERTICAL", - value: 1, - description: "Layout is defined by a vertical line with faces" - }, - { - name: "CUBEMAP_LAYOUT_LINE_HORIZONTAL", - value: 2, - description: "Layout is defined by a horizontal line with faces" - }, - { - name: "CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR", - value: 3, - description: "Layout is defined by a 3x4 cross with cubemap faces" - }, - { - name: "CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE", - value: 4, - description: "Layout is defined by a 4x3 cross with cubemap faces" - } - ] - }, - { - name: "FontType", - description: "Font type, defines generation method", - values: [ - { - name: "FONT_DEFAULT", - value: 0, - description: "Default font generation, anti-aliased" - }, - { - name: "FONT_BITMAP", - value: 1, - description: "Bitmap font generation, no anti-aliasing" - }, - { - name: "FONT_SDF", - value: 2, - description: "SDF font generation, requires external shader" - } - ] - }, - { - name: "BlendMode", - description: "Color blending modes (pre-defined)", - values: [ - { - name: "BLEND_ALPHA", - value: 0, - description: "Blend textures considering alpha (default)" - }, - { - name: "BLEND_ADDITIVE", - value: 1, - description: "Blend textures adding colors" - }, - { - name: "BLEND_MULTIPLIED", - value: 2, - description: "Blend textures multiplying colors" - }, - { - name: "BLEND_ADD_COLORS", - value: 3, - description: "Blend textures adding colors (alternative)" - }, - { - name: "BLEND_SUBTRACT_COLORS", - value: 4, - description: "Blend textures subtracting colors (alternative)" - }, - { - name: "BLEND_ALPHA_PREMULTIPLY", - value: 5, - description: "Blend premultiplied textures considering alpha" - }, - { - name: "BLEND_CUSTOM", - value: 6, - description: "Blend textures using custom src/dst factors (use rlSetBlendFactors())" - }, - { - name: "BLEND_CUSTOM_SEPARATE", - value: 7, - description: "Blend textures using custom rgb/alpha separate src/dst factors (use rlSetBlendFactorsSeparate())" - } - ] - }, - { - name: "Gesture", - description: "Gesture", - values: [ - { - name: "GESTURE_NONE", - value: 0, - description: "No gesture" - }, - { - name: "GESTURE_TAP", - value: 1, - description: "Tap gesture" - }, - { - name: "GESTURE_DOUBLETAP", - value: 2, - description: "Double tap gesture" - }, - { - name: "GESTURE_HOLD", - value: 4, - description: "Hold gesture" - }, - { - name: "GESTURE_DRAG", - value: 8, - description: "Drag gesture" - }, - { - name: "GESTURE_SWIPE_RIGHT", - value: 16, - description: "Swipe right gesture" - }, - { - name: "GESTURE_SWIPE_LEFT", - value: 32, - description: "Swipe left gesture" - }, - { - name: "GESTURE_SWIPE_UP", - value: 64, - description: "Swipe up gesture" - }, - { - name: "GESTURE_SWIPE_DOWN", - value: 128, - description: "Swipe down gesture" - }, - { - name: "GESTURE_PINCH_IN", - value: 256, - description: "Pinch in gesture" - }, - { - name: "GESTURE_PINCH_OUT", - value: 512, - description: "Pinch out gesture" - } - ] - }, - { - name: "CameraMode", - description: "Camera system modes", - values: [ - { - name: "CAMERA_CUSTOM", - value: 0, - description: "Camera custom, controlled by user (UpdateCamera() does nothing)" - }, - { - name: "CAMERA_FREE", - value: 1, - description: "Camera free mode" - }, - { - name: "CAMERA_ORBITAL", - value: 2, - description: "Camera orbital, around target, zoom supported" - }, - { - name: "CAMERA_FIRST_PERSON", - value: 3, - description: "Camera first person" - }, - { - name: "CAMERA_THIRD_PERSON", - value: 4, - description: "Camera third person" - } - ] - }, - { - name: "CameraProjection", - description: "Camera projection", - values: [ - { - name: "CAMERA_PERSPECTIVE", - value: 0, - description: "Perspective projection" - }, - { - name: "CAMERA_ORTHOGRAPHIC", - value: 1, - description: "Orthographic projection" - } - ] - }, - { - name: "NPatchLayout", - description: "N-patch layout", - values: [ - { - name: "NPATCH_NINE_PATCH", - value: 0, - description: "Npatch layout: 3x3 tiles" - }, - { - name: "NPATCH_THREE_PATCH_VERTICAL", - value: 1, - description: "Npatch layout: 1x3 tiles" - }, - { - name: "NPATCH_THREE_PATCH_HORIZONTAL", - value: 2, - description: "Npatch layout: 3x1 tiles" - } - ] - } - ], - callbacks: [ - { - name: "TraceLogCallback", - description: "Logging: Redirect trace log messages", - returnType: "void", - params: [ - {type: "int", name: "logLevel"}, - {type: "const char *", name: "text"}, - {type: "va_list", name: "args"} - ] - }, - { - name: "LoadFileDataCallback", - description: "FileIO: Load binary data", - returnType: "unsigned char *", - params: [ - {type: "const char *", name: "fileName"}, - {type: "int *", name: "dataSize"} - ] - }, - { - name: "SaveFileDataCallback", - description: "FileIO: Save binary data", - returnType: "bool", - params: [ - {type: "const char *", name: "fileName"}, - {type: "const void *", name: "data"}, - {type: "int", name: "dataSize"} - ] - }, - { - name: "LoadFileTextCallback", - description: "FileIO: Load text data", - returnType: "char *", - params: [ - {type: "const char *", name: "fileName"} - ] - }, - { - name: "SaveFileTextCallback", - description: "FileIO: Save text data", - returnType: "bool", - params: [ - {type: "const char *", name: "fileName"}, - {type: "const char *", name: "text"} - ] - }, - { - name: "AudioCallback", - description: "", - returnType: "void", - params: [ - {type: "void *", name: "bufferData"}, - {type: "unsigned int", name: "frames"} - ] - } - ], - functions: [ - { - name: "InitWindow", - description: "Initialize window and OpenGL context", - returnType: "void", - params: [ - {type: "int", name: "width"}, - {type: "int", name: "height"}, - {type: "const char *", name: "title"} - ] - }, - { - name: "CloseWindow", - description: "Close window and unload OpenGL context", - returnType: "void" - }, - { - name: "WindowShouldClose", - description: "Check if application should close (KEY_ESCAPE pressed or windows close icon clicked)", - returnType: "bool" - }, - { - name: "IsWindowReady", - description: "Check if window has been initialized successfully", - returnType: "bool" - }, - { - name: "IsWindowFullscreen", - description: "Check if window is currently fullscreen", - returnType: "bool" - }, - { - name: "IsWindowHidden", - description: "Check if window is currently hidden", - returnType: "bool" - }, - { - name: "IsWindowMinimized", - description: "Check if window is currently minimized", - returnType: "bool" - }, - { - name: "IsWindowMaximized", - description: "Check if window is currently maximized", - returnType: "bool" - }, - { - name: "IsWindowFocused", - description: "Check if window is currently focused", - returnType: "bool" - }, - { - name: "IsWindowResized", - description: "Check if window has been resized last frame", - returnType: "bool" - }, - { - name: "IsWindowState", - description: "Check if one specific window flag is enabled", - returnType: "bool", - params: [ - {type: "unsigned int", name: "flag"} - ] - }, - { - name: "SetWindowState", - description: "Set window configuration state using flags", - returnType: "void", - params: [ - {type: "unsigned int", name: "flags"} - ] - }, - { - name: "ClearWindowState", - description: "Clear window configuration state flags", - returnType: "void", - params: [ - {type: "unsigned int", name: "flags"} - ] - }, - { - name: "ToggleFullscreen", - description: "Toggle window state: fullscreen/windowed, resizes monitor to match window resolution", - returnType: "void" - }, - { - name: "ToggleBorderlessWindowed", - description: "Toggle window state: borderless windowed, resizes window to match monitor resolution", - returnType: "void" - }, - { - name: "MaximizeWindow", - description: "Set window state: maximized, if resizable", - returnType: "void" - }, - { - name: "MinimizeWindow", - description: "Set window state: minimized, if resizable", - returnType: "void" - }, - { - name: "RestoreWindow", - description: "Restore window from being minimized/maximized", - returnType: "void" - }, - { - name: "SetWindowIcon", - description: "Set icon for window (single image, RGBA 32bit)", - returnType: "void", - params: [ - {type: "Image", name: "image"} - ] - }, - { - name: "SetWindowIcons", - description: "Set icon for window (multiple images, RGBA 32bit)", - returnType: "void", - params: [ - {type: "Image *", name: "images"}, - {type: "int", name: "count"} - ] - }, - { - name: "SetWindowTitle", - description: "Set title for window", - returnType: "void", - params: [ - {type: "const char *", name: "title"} - ] - }, - { - name: "SetWindowPosition", - description: "Set window position on screen", - returnType: "void", - params: [ - {type: "int", name: "x"}, - {type: "int", name: "y"} - ] - }, - { - name: "SetWindowMonitor", - description: "Set monitor for the current window", - returnType: "void", - params: [ - {type: "int", name: "monitor"} - ] - }, - { - name: "SetWindowMinSize", - description: "Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE)", - returnType: "void", - params: [ - {type: "int", name: "width"}, - {type: "int", name: "height"} - ] - }, - { - name: "SetWindowMaxSize", - description: "Set window maximum dimensions (for FLAG_WINDOW_RESIZABLE)", - returnType: "void", - params: [ - {type: "int", name: "width"}, - {type: "int", name: "height"} - ] - }, - { - name: "SetWindowSize", - description: "Set window dimensions", - returnType: "void", - params: [ - {type: "int", name: "width"}, - {type: "int", name: "height"} - ] - }, - { - name: "SetWindowOpacity", - description: "Set window opacity [0.0f..1.0f]", - returnType: "void", - params: [ - {type: "float", name: "opacity"} - ] - }, - { - name: "SetWindowFocused", - description: "Set window focused", - returnType: "void" - }, - { - name: "GetWindowHandle", - description: "Get native window handle", - returnType: "void *" - }, - { - name: "GetScreenWidth", - description: "Get current screen width", - returnType: "int" - }, - { - name: "GetScreenHeight", - description: "Get current screen height", - returnType: "int" - }, - { - name: "GetRenderWidth", - description: "Get current render width (it considers HiDPI)", - returnType: "int" - }, - { - name: "GetRenderHeight", - description: "Get current render height (it considers HiDPI)", - returnType: "int" - }, - { - name: "GetMonitorCount", - description: "Get number of connected monitors", - returnType: "int" - }, - { - name: "GetCurrentMonitor", - description: "Get current monitor where window is placed", - returnType: "int" - }, - { - name: "GetMonitorPosition", - description: "Get specified monitor position", - returnType: "Vector2", - params: [ - {type: "int", name: "monitor"} - ] - }, - { - name: "GetMonitorWidth", - description: "Get specified monitor width (current video mode used by monitor)", - returnType: "int", - params: [ - {type: "int", name: "monitor"} - ] - }, - { - name: "GetMonitorHeight", - description: "Get specified monitor height (current video mode used by monitor)", - returnType: "int", - params: [ - {type: "int", name: "monitor"} - ] - }, - { - name: "GetMonitorPhysicalWidth", - description: "Get specified monitor physical width in millimetres", - returnType: "int", - params: [ - {type: "int", name: "monitor"} - ] - }, - { - name: "GetMonitorPhysicalHeight", - description: "Get specified monitor physical height in millimetres", - returnType: "int", - params: [ - {type: "int", name: "monitor"} - ] - }, - { - name: "GetMonitorRefreshRate", - description: "Get specified monitor refresh rate", - returnType: "int", - params: [ - {type: "int", name: "monitor"} - ] - }, - { - name: "GetWindowPosition", - description: "Get window position XY on monitor", - returnType: "Vector2" - }, - { - name: "GetWindowScaleDPI", - description: "Get window scale DPI factor", - returnType: "Vector2" - }, - { - name: "GetMonitorName", - description: "Get the human-readable, UTF-8 encoded name of the specified monitor", - returnType: "const char *", - params: [ - {type: "int", name: "monitor"} - ] - }, - { - name: "SetClipboardText", - description: "Set clipboard text content", - returnType: "void", - params: [ - {type: "const char *", name: "text"} - ] - }, - { - name: "GetClipboardText", - description: "Get clipboard text content", - returnType: "const char *" - }, - { - name: "GetClipboardImage", - description: "Get clipboard image content", - returnType: "Image" - }, - { - name: "EnableEventWaiting", - description: "Enable waiting for events on EndDrawing(), no automatic event polling", - returnType: "void" - }, - { - name: "DisableEventWaiting", - description: "Disable waiting for events on EndDrawing(), automatic events polling", - returnType: "void" - }, - { - name: "ShowCursor", - description: "Show cursor", - returnType: "void" - }, - { - name: "HideCursor", - description: "Hide cursor", - returnType: "void" - }, - { - name: "IsCursorHidden", - description: "Check if cursor is not visible", - returnType: "bool" - }, - { - name: "EnableCursor", - description: "Enable cursor (unlock cursor)", - returnType: "void" - }, - { - name: "DisableCursor", - description: "Disable cursor (lock cursor)", - returnType: "void" - }, - { - name: "IsCursorOnScreen", - description: "Check if cursor is on the screen", - returnType: "bool" - }, - { - name: "ClearBackground", - description: "Clear background (framebuffer) to color", - returnType: "void", - params: [ - {type: "Color", name: "color"} - ] - }, - { - name: "BeginDrawing", - description: "Begin canvas (framebuffer) drawing", - returnType: "void" - }, - { - name: "EndDrawing", - description: "End canvas (framebuffer) drawing and swap buffers (double buffering)", - returnType: "void" - }, - { - name: "BeginMode2D", - description: "Begin 2D mode with custom camera (2D)", - returnType: "void", - params: [ - {type: "Camera2D", name: "camera"} - ] - }, - { - name: "EndMode2D", - description: "End 2D mode with custom camera", - returnType: "void" - }, - { - name: "BeginMode3D", - description: "Begin 3D mode with custom camera (3D)", - returnType: "void", - params: [ - {type: "Camera3D", name: "camera"} - ] - }, - { - name: "EndMode3D", - description: "End 3D mode and returns to default 2D orthographic mode", - returnType: "void" - }, - { - name: "BeginTextureMode", - description: "Begin drawing to render texture", - returnType: "void", - params: [ - {type: "RenderTexture2D", name: "target"} - ] - }, - { - name: "EndTextureMode", - description: "End drawing to render texture", - returnType: "void" - }, - { - name: "BeginShaderMode", - description: "Begin custom shader drawing", - returnType: "void", - params: [ - {type: "Shader", name: "shader"} - ] - }, - { - name: "EndShaderMode", - description: "End custom shader drawing (use default shader)", - returnType: "void" - }, - { - name: "BeginBlendMode", - description: "Begin blending mode (alpha, additive, multiplied, subtract, custom)", - returnType: "void", - params: [ - {type: "int", name: "mode"} - ] - }, - { - name: "EndBlendMode", - description: "End blending mode (reset to default: alpha blending)", - returnType: "void" - }, - { - name: "BeginScissorMode", - description: "Begin scissor mode (define screen area for following drawing)", - returnType: "void", - params: [ - {type: "int", name: "x"}, - {type: "int", name: "y"}, - {type: "int", name: "width"}, - {type: "int", name: "height"} - ] - }, - { - name: "EndScissorMode", - description: "End scissor mode", - returnType: "void" - }, - { - name: "BeginVrStereoMode", - description: "Begin stereo rendering (requires VR simulator)", - returnType: "void", - params: [ - {type: "VrStereoConfig", name: "config"} - ] - }, - { - name: "EndVrStereoMode", - description: "End stereo rendering (requires VR simulator)", - returnType: "void" - }, - { - name: "LoadVrStereoConfig", - description: "Load VR stereo config for VR simulator device parameters", - returnType: "VrStereoConfig", - params: [ - {type: "VrDeviceInfo", name: "device"} - ] - }, - { - name: "UnloadVrStereoConfig", - description: "Unload VR stereo config", - returnType: "void", - params: [ - {type: "VrStereoConfig", name: "config"} - ] - }, - { - name: "LoadShader", - description: "Load shader from files and bind default locations", - returnType: "Shader", - params: [ - {type: "const char *", name: "vsFileName"}, - {type: "const char *", name: "fsFileName"} - ] - }, - { - name: "LoadShaderFromMemory", - description: "Load shader from code strings and bind default locations", - returnType: "Shader", - params: [ - {type: "const char *", name: "vsCode"}, - {type: "const char *", name: "fsCode"} - ] - }, - { - name: "IsShaderValid", - description: "Check if shader is valid (loaded on GPU)", - returnType: "bool", - params: [ - {type: "Shader", name: "shader"} - ] - }, - { - name: "GetShaderLocation", - description: "Get shader uniform location", - returnType: "int", - params: [ - {type: "Shader", name: "shader"}, - {type: "const char *", name: "uniformName"} - ] - }, - { - name: "GetShaderLocationAttrib", - description: "Get shader attribute location", - returnType: "int", - params: [ - {type: "Shader", name: "shader"}, - {type: "const char *", name: "attribName"} - ] - }, - { - name: "SetShaderValue", - description: "Set shader uniform value", - returnType: "void", - params: [ - {type: "Shader", name: "shader"}, - {type: "int", name: "locIndex"}, - {type: "const void *", name: "value"}, - {type: "int", name: "uniformType"} - ] - }, - { - name: "SetShaderValueV", - description: "Set shader uniform value vector", - returnType: "void", - params: [ - {type: "Shader", name: "shader"}, - {type: "int", name: "locIndex"}, - {type: "const void *", name: "value"}, - {type: "int", name: "uniformType"}, - {type: "int", name: "count"} - ] - }, - { - name: "SetShaderValueMatrix", - description: "Set shader uniform value (matrix 4x4)", - returnType: "void", - params: [ - {type: "Shader", name: "shader"}, - {type: "int", name: "locIndex"}, - {type: "Matrix", name: "mat"} - ] - }, - { - name: "SetShaderValueTexture", - description: "Set shader uniform value and bind the texture (sampler2d)", - returnType: "void", - params: [ - {type: "Shader", name: "shader"}, - {type: "int", name: "locIndex"}, - {type: "Texture2D", name: "texture"} - ] - }, - { - name: "UnloadShader", - description: "Unload shader from GPU memory (VRAM)", - returnType: "void", - params: [ - {type: "Shader", name: "shader"} - ] - }, - { - name: "GetScreenToWorldRay", - description: "Get a ray trace from screen position (i.e mouse)", - returnType: "Ray", - params: [ - {type: "Vector2", name: "position"}, - {type: "Camera", name: "camera"} - ] - }, - { - name: "GetScreenToWorldRayEx", - description: "Get a ray trace from screen position (i.e mouse) in a viewport", - returnType: "Ray", - params: [ - {type: "Vector2", name: "position"}, - {type: "Camera", name: "camera"}, - {type: "int", name: "width"}, - {type: "int", name: "height"} - ] - }, - { - name: "GetWorldToScreen", - description: "Get screen space position for a 3d world space position", - returnType: "Vector2", - params: [ - {type: "Vector3", name: "position"}, - {type: "Camera", name: "camera"} - ] - }, - { - name: "GetWorldToScreenEx", - description: "Get sized screen space position for a 3d world space position", - returnType: "Vector2", - params: [ - {type: "Vector3", name: "position"}, - {type: "Camera", name: "camera"}, - {type: "int", name: "width"}, - {type: "int", name: "height"} - ] - }, - { - name: "GetWorldToScreen2D", - description: "Get screen space position for a 2d camera world space position", - returnType: "Vector2", - params: [ - {type: "Vector2", name: "position"}, - {type: "Camera2D", name: "camera"} - ] - }, - { - name: "GetScreenToWorld2D", - description: "Get world space position for a 2d camera screen space position", - returnType: "Vector2", - params: [ - {type: "Vector2", name: "position"}, - {type: "Camera2D", name: "camera"} - ] - }, - { - name: "GetCameraMatrix", - description: "Get camera transform matrix (view matrix)", - returnType: "Matrix", - params: [ - {type: "Camera", name: "camera"} - ] - }, - { - name: "GetCameraMatrix2D", - description: "Get camera 2d transform matrix", - returnType: "Matrix", - params: [ - {type: "Camera2D", name: "camera"} - ] - }, - { - name: "SetTargetFPS", - description: "Set target FPS (maximum)", - returnType: "void", - params: [ - {type: "int", name: "fps"} - ] - }, - { - name: "GetFrameTime", - description: "Get time in seconds for last frame drawn (delta time)", - returnType: "float" - }, - { - name: "GetTime", - description: "Get elapsed time in seconds since InitWindow()", - returnType: "double" - }, - { - name: "GetFPS", - description: "Get current FPS", - returnType: "int" - }, - { - name: "SwapScreenBuffer", - description: "Swap back buffer with front buffer (screen drawing)", - returnType: "void" - }, - { - name: "PollInputEvents", - description: "Register all input events", - returnType: "void" - }, - { - name: "WaitTime", - description: "Wait for some time (halt program execution)", - returnType: "void", - params: [ - {type: "double", name: "seconds"} - ] - }, - { - name: "SetRandomSeed", - description: "Set the seed for the random number generator", - returnType: "void", - params: [ - {type: "unsigned int", name: "seed"} - ] - }, - { - name: "GetRandomValue", - description: "Get a random value between min and max (both included)", - returnType: "int", - params: [ - {type: "int", name: "min"}, - {type: "int", name: "max"} - ] - }, - { - name: "LoadRandomSequence", - description: "Load random values sequence, no values repeated", - returnType: "int *", - params: [ - {type: "unsigned int", name: "count"}, - {type: "int", name: "min"}, - {type: "int", name: "max"} - ] - }, - { - name: "UnloadRandomSequence", - description: "Unload random values sequence", - returnType: "void", - params: [ - {type: "int *", name: "sequence"} - ] - }, - { - name: "TakeScreenshot", - description: "Takes a screenshot of current screen (filename extension defines format)", - returnType: "void", - params: [ - {type: "const char *", name: "fileName"} - ] - }, - { - name: "SetConfigFlags", - description: "Set up init configuration flags (view FLAGS)", - returnType: "void", - params: [ - {type: "unsigned int", name: "flags"} - ] - }, - { - name: "OpenURL", - description: "Open URL with default system browser (if available)", - returnType: "void", - params: [ - {type: "const char *", name: "url"} - ] - }, - { - name: "SetTraceLogLevel", - description: "Set the current threshold (minimum) log level", - returnType: "void", - params: [ - {type: "int", name: "logLevel"} - ] - }, - { - name: "TraceLog", - description: "Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...)", - returnType: "void", - params: [ - {type: "int", name: "logLevel"}, - {type: "const char *", name: "text"}, - {type: "...", name: "args"} - ] - }, - { - name: "SetTraceLogCallback", - description: "Set custom trace log", - returnType: "void", - params: [ - {type: "TraceLogCallback", name: "callback"} - ] - }, - { - name: "MemAlloc", - description: "Internal memory allocator", - returnType: "void *", - params: [ - {type: "unsigned int", name: "size"} - ] - }, - { - name: "MemRealloc", - description: "Internal memory reallocator", - returnType: "void *", - params: [ - {type: "void *", name: "ptr"}, - {type: "unsigned int", name: "size"} - ] - }, - { - name: "MemFree", - description: "Internal memory free", - returnType: "void", - params: [ - {type: "void *", name: "ptr"} - ] - }, - { - name: "LoadFileData", - description: "Load file data as byte array (read)", - returnType: "unsigned char *", - params: [ - {type: "const char *", name: "fileName"}, - {type: "int *", name: "dataSize"} - ] - }, - { - name: "UnloadFileData", - description: "Unload file data allocated by LoadFileData()", - returnType: "void", - params: [ - {type: "unsigned char *", name: "data"} - ] - }, - { - name: "SaveFileData", - description: "Save data to file from byte array (write), returns true on success", - returnType: "bool", - params: [ - {type: "const char *", name: "fileName"}, - {type: "const void *", name: "data"}, - {type: "int", name: "dataSize"} - ] - }, - { - name: "ExportDataAsCode", - description: "Export data to code (.h), returns true on success", - returnType: "bool", - params: [ - {type: "const unsigned char *", name: "data"}, - {type: "int", name: "dataSize"}, - {type: "const char *", name: "fileName"} - ] - }, - { - name: "LoadFileText", - description: "Load text data from file (read), returns a '\\0' terminated string", - returnType: "char *", - params: [ - {type: "const char *", name: "fileName"} - ] - }, - { - name: "UnloadFileText", - description: "Unload file text data allocated by LoadFileText()", - returnType: "void", - params: [ - {type: "char *", name: "text"} - ] - }, - { - name: "SaveFileText", - description: "Save text data to file (write), string must be '\\0' terminated, returns true on success", - returnType: "bool", - params: [ - {type: "const char *", name: "fileName"}, - {type: "const char *", name: "text"} - ] - }, - { - name: "SetLoadFileDataCallback", - description: "Set custom file binary data loader", - returnType: "void", - params: [ - {type: "LoadFileDataCallback", name: "callback"} - ] - }, - { - name: "SetSaveFileDataCallback", - description: "Set custom file binary data saver", - returnType: "void", - params: [ - {type: "SaveFileDataCallback", name: "callback"} - ] - }, - { - name: "SetLoadFileTextCallback", - description: "Set custom file text data loader", - returnType: "void", - params: [ - {type: "LoadFileTextCallback", name: "callback"} - ] - }, - { - name: "SetSaveFileTextCallback", - description: "Set custom file text data saver", - returnType: "void", - params: [ - {type: "SaveFileTextCallback", name: "callback"} - ] - }, - { - name: "FileRename", - description: "Rename file (if exists), returns 0 on success", - returnType: "int", - params: [ - {type: "const char *", name: "fileName"}, - {type: "const char *", name: "fileRename"} - ] - }, - { - name: "FileRemove", - description: "Remove file (if exists), returns 0 on success", - returnType: "int", - params: [ - {type: "const char *", name: "fileName"} - ] - }, - { - name: "FileCopy", - description: "Copy file from one path to another, dstPath created if it doesn't exist, returns 0 on success", - returnType: "int", - params: [ - {type: "const char *", name: "srcPath"}, - {type: "const char *", name: "dstPath"} - ] - }, - { - name: "FileMove", - description: "Move file from one directory to another, dstPath created if it doesn't exist, returns 0 on success", - returnType: "int", - params: [ - {type: "const char *", name: "srcPath"}, - {type: "const char *", name: "dstPath"} - ] - }, - { - name: "FileTextReplace", - description: "Replace text in an existing file, returns 0 on success", - returnType: "int", - params: [ - {type: "const char *", name: "fileName"}, - {type: "const char *", name: "search"}, - {type: "const char *", name: "replacement"} - ] - }, - { - name: "FileTextFindIndex", - description: "Find text in existing file, returns -1 if index not found or index otherwise", - returnType: "int", - params: [ - {type: "const char *", name: "fileName"}, - {type: "const char *", name: "search"} - ] - }, - { - name: "FileExists", - description: "Check if file exists", - returnType: "bool", - params: [ - {type: "const char *", name: "fileName"} - ] - }, - { - name: "DirectoryExists", - description: "Check if directory path exists", - returnType: "bool", - params: [ - {type: "const char *", name: "dirPath"} - ] - }, - { - name: "IsFileExtension", - description: "Check file extension (recommended include point: .png, .wav)", - returnType: "bool", - params: [ - {type: "const char *", name: "fileName"}, - {type: "const char *", name: "ext"} - ] - }, - { - name: "GetFileLength", - description: "Get file length in bytes (NOTE: GetFileSize() conflicts with windows.h)", - returnType: "int", - params: [ - {type: "const char *", name: "fileName"} - ] - }, - { - name: "GetFileModTime", - description: "Get file modification time (last write time)", - returnType: "long", - params: [ - {type: "const char *", name: "fileName"} - ] - }, - { - name: "GetFileExtension", - description: "Get pointer to extension for a filename string (includes dot: '.png')", - returnType: "const char *", - params: [ - {type: "const char *", name: "fileName"} - ] - }, - { - name: "GetFileName", - description: "Get pointer to filename for a path string", - returnType: "const char *", - params: [ - {type: "const char *", name: "filePath"} - ] - }, - { - name: "GetFileNameWithoutExt", - description: "Get filename string without extension (uses static string)", - returnType: "const char *", - params: [ - {type: "const char *", name: "filePath"} - ] - }, - { - name: "GetDirectoryPath", - description: "Get full path for a given fileName with path (uses static string)", - returnType: "const char *", - params: [ - {type: "const char *", name: "filePath"} - ] - }, - { - name: "GetPrevDirectoryPath", - description: "Get previous directory path for a given path (uses static string)", - returnType: "const char *", - params: [ - {type: "const char *", name: "dirPath"} - ] - }, - { - name: "GetWorkingDirectory", - description: "Get current working directory (uses static string)", - returnType: "const char *" - }, - { - name: "GetApplicationDirectory", - description: "Get the directory of the running application (uses static string)", - returnType: "const char *" - }, - { - name: "MakeDirectory", - description: "Create directories (including full path requested), returns 0 on success", - returnType: "int", - params: [ - {type: "const char *", name: "dirPath"} - ] - }, - { - name: "ChangeDirectory", - description: "Change working directory, returns 0 on success", - returnType: "int", - params: [ - {type: "const char *", name: "dirPath"} - ] - }, - { - name: "IsPathFile", - description: "Check if given path is a file or a directory", - returnType: "bool", - params: [ - {type: "const char *", name: "path"} - ] - }, - { - name: "IsFileNameValid", - description: "Check if fileName is valid for the platform/OS", - returnType: "bool", - params: [ - {type: "const char *", name: "fileName"} - ] - }, - { - name: "LoadDirectoryFiles", - description: "Load directory filepaths, files and directories, no subdirs scan", - returnType: "FilePathList", - params: [ - {type: "const char *", name: "dirPath"} - ] - }, - { - name: "LoadDirectoryFilesEx", - description: "Load directory filepaths with extension filtering and subdir scan; some filters available: '*.*','FILES*','DIRS*'", - returnType: "FilePathList", - params: [ - {type: "const char *", name: "basePath"}, - {type: "const char *", name: "filter"}, - {type: "bool", name: "scanSubdirs"} - ] - }, - { - name: "UnloadDirectoryFiles", - description: "Unload filepaths", - returnType: "void", - params: [ - {type: "FilePathList", name: "files"} - ] - }, - { - name: "IsFileDropped", - description: "Check if file has been dropped into window", - returnType: "bool" - }, - { - name: "LoadDroppedFiles", - description: "Load dropped filepaths", - returnType: "FilePathList" - }, - { - name: "UnloadDroppedFiles", - description: "Unload dropped filepaths", - returnType: "void", - params: [ - {type: "FilePathList", name: "files"} - ] - }, - { - name: "GetDirectoryFileCount", - description: "Get the file count in a directory", - returnType: "unsigned int", - params: [ - {type: "const char *", name: "dirPath"} - ] - }, - { - name: "GetDirectoryFileCountEx", - description: "Get the file count in a directory with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result", - returnType: "unsigned int", - params: [ - {type: "const char *", name: "basePath"}, - {type: "const char *", name: "filter"}, - {type: "bool", name: "scanSubdirs"} - ] - }, - { - name: "CompressData", - description: "Compress data (DEFLATE algorithm), memory must be MemFree()", - returnType: "unsigned char *", - params: [ - {type: "const unsigned char *", name: "data"}, - {type: "int", name: "dataSize"}, - {type: "int *", name: "compDataSize"} - ] - }, - { - name: "DecompressData", - description: "Decompress data (DEFLATE algorithm), memory must be MemFree()", - returnType: "unsigned char *", - params: [ - {type: "const unsigned char *", name: "compData"}, - {type: "int", name: "compDataSize"}, - {type: "int *", name: "dataSize"} - ] - }, - { - name: "EncodeDataBase64", - description: "Encode data to Base64 string (includes NULL terminator), memory must be MemFree()", - returnType: "char *", - params: [ - {type: "const unsigned char *", name: "data"}, - {type: "int", name: "dataSize"}, - {type: "int *", name: "outputSize"} - ] - }, - { - name: "DecodeDataBase64", - description: "Decode Base64 string (expected NULL terminated), memory must be MemFree()", - returnType: "unsigned char *", - params: [ - {type: "const char *", name: "text"}, - {type: "int *", name: "outputSize"} - ] - }, - { - name: "ComputeCRC32", - description: "Compute CRC32 hash code", - returnType: "unsigned int", - params: [ - {type: "const unsigned char *", name: "data"}, - {type: "int", name: "dataSize"} - ] - }, - { - name: "ComputeMD5", - description: "Compute MD5 hash code, returns static int[4] (16 bytes)", - returnType: "unsigned int *", - params: [ - {type: "const unsigned char *", name: "data"}, - {type: "int", name: "dataSize"} - ] - }, - { - name: "ComputeSHA1", - description: "Compute SHA1 hash code, returns static int[5] (20 bytes)", - returnType: "unsigned int *", - params: [ - {type: "const unsigned char *", name: "data"}, - {type: "int", name: "dataSize"} - ] - }, - { - name: "ComputeSHA256", - description: "Compute SHA256 hash code, returns static int[8] (32 bytes)", - returnType: "unsigned int *", - params: [ - {type: "const unsigned char *", name: "data"}, - {type: "int", name: "dataSize"} - ] - }, - { - name: "LoadAutomationEventList", - description: "Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS", - returnType: "AutomationEventList", - params: [ - {type: "const char *", name: "fileName"} - ] - }, - { - name: "UnloadAutomationEventList", - description: "Unload automation events list from file", - returnType: "void", - params: [ - {type: "AutomationEventList", name: "list"} - ] - }, - { - name: "ExportAutomationEventList", - description: "Export automation events list as text file", - returnType: "bool", - params: [ - {type: "AutomationEventList", name: "list"}, - {type: "const char *", name: "fileName"} - ] - }, - { - name: "SetAutomationEventList", - description: "Set automation event list to record to", - returnType: "void", - params: [ - {type: "AutomationEventList *", name: "list"} - ] - }, - { - name: "SetAutomationEventBaseFrame", - description: "Set automation event internal base frame to start recording", - returnType: "void", - params: [ - {type: "int", name: "frame"} - ] - }, - { - name: "StartAutomationEventRecording", - description: "Start recording automation events (AutomationEventList must be set)", - returnType: "void" - }, - { - name: "StopAutomationEventRecording", - description: "Stop recording automation events", - returnType: "void" - }, - { - name: "PlayAutomationEvent", - description: "Play a recorded automation event", - returnType: "void", - params: [ - {type: "AutomationEvent", name: "event"} - ] - }, - { - name: "IsKeyPressed", - description: "Check if key has been pressed once", - returnType: "bool", - params: [ - {type: "int", name: "key"} - ] - }, - { - name: "IsKeyPressedRepeat", - description: "Check if key has been pressed again", - returnType: "bool", - params: [ - {type: "int", name: "key"} - ] - }, - { - name: "IsKeyDown", - description: "Check if key is being pressed", - returnType: "bool", - params: [ - {type: "int", name: "key"} - ] - }, - { - name: "IsKeyReleased", - description: "Check if key has been released once", - returnType: "bool", - params: [ - {type: "int", name: "key"} - ] - }, - { - name: "IsKeyUp", - description: "Check if key is NOT being pressed", - returnType: "bool", - params: [ - {type: "int", name: "key"} - ] - }, - { - name: "GetKeyPressed", - description: "Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty", - returnType: "int" - }, - { - name: "GetCharPressed", - description: "Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty", - returnType: "int" - }, - { - name: "GetKeyName", - description: "Get name of a QWERTY key on the current keyboard layout (eg returns string 'q' for KEY_A on an AZERTY keyboard)", - returnType: "const char *", - params: [ - {type: "int", name: "key"} - ] - }, - { - name: "SetExitKey", - description: "Set a custom key to exit program (default is ESC)", - returnType: "void", - params: [ - {type: "int", name: "key"} - ] - }, - { - name: "IsGamepadAvailable", - description: "Check if gamepad is available", - returnType: "bool", - params: [ - {type: "int", name: "gamepad"} - ] - }, - { - name: "GetGamepadName", - description: "Get gamepad internal name id", - returnType: "const char *", - params: [ - {type: "int", name: "gamepad"} - ] - }, - { - name: "IsGamepadButtonPressed", - description: "Check if gamepad button has been pressed once", - returnType: "bool", - params: [ - {type: "int", name: "gamepad"}, - {type: "int", name: "button"} - ] - }, - { - name: "IsGamepadButtonDown", - description: "Check if gamepad button is being pressed", - returnType: "bool", - params: [ - {type: "int", name: "gamepad"}, - {type: "int", name: "button"} - ] - }, - { - name: "IsGamepadButtonReleased", - description: "Check if gamepad button has been released once", - returnType: "bool", - params: [ - {type: "int", name: "gamepad"}, - {type: "int", name: "button"} - ] - }, - { - name: "IsGamepadButtonUp", - description: "Check if gamepad button is NOT being pressed", - returnType: "bool", - params: [ - {type: "int", name: "gamepad"}, - {type: "int", name: "button"} - ] - }, - { - name: "GetGamepadButtonPressed", - description: "Get the last gamepad button pressed", - returnType: "int" - }, - { - name: "GetGamepadAxisCount", - description: "Get axis count for a gamepad", - returnType: "int", - params: [ - {type: "int", name: "gamepad"} - ] - }, - { - name: "GetGamepadAxisMovement", - description: "Get movement value for a gamepad axis", - returnType: "float", - params: [ - {type: "int", name: "gamepad"}, - {type: "int", name: "axis"} - ] - }, - { - name: "SetGamepadMappings", - description: "Set internal gamepad mappings (SDL_GameControllerDB)", - returnType: "int", - params: [ - {type: "const char *", name: "mappings"} - ] - }, - { - name: "SetGamepadVibration", - description: "Set gamepad vibration for both motors (duration in seconds)", - returnType: "void", - params: [ - {type: "int", name: "gamepad"}, - {type: "float", name: "leftMotor"}, - {type: "float", name: "rightMotor"}, - {type: "float", name: "duration"} - ] - }, - { - name: "IsMouseButtonPressed", - description: "Check if mouse button has been pressed once", - returnType: "bool", - params: [ - {type: "int", name: "button"} - ] - }, - { - name: "IsMouseButtonDown", - description: "Check if mouse button is being pressed", - returnType: "bool", - params: [ - {type: "int", name: "button"} - ] - }, - { - name: "IsMouseButtonReleased", - description: "Check if mouse button has been released once", - returnType: "bool", - params: [ - {type: "int", name: "button"} - ] - }, - { - name: "IsMouseButtonUp", - description: "Check if mouse button is NOT being pressed", - returnType: "bool", - params: [ - {type: "int", name: "button"} - ] - }, - { - name: "GetMouseX", - description: "Get mouse position X", - returnType: "int" - }, - { - name: "GetMouseY", - description: "Get mouse position Y", - returnType: "int" - }, - { - name: "GetMousePosition", - description: "Get mouse position XY", - returnType: "Vector2" - }, - { - name: "GetMouseDelta", - description: "Get mouse delta between frames", - returnType: "Vector2" - }, - { - name: "SetMousePosition", - description: "Set mouse position XY", - returnType: "void", - params: [ - {type: "int", name: "x"}, - {type: "int", name: "y"} - ] - }, - { - name: "SetMouseOffset", - description: "Set mouse offset", - returnType: "void", - params: [ - {type: "int", name: "offsetX"}, - {type: "int", name: "offsetY"} - ] - }, - { - name: "SetMouseScale", - description: "Set mouse scaling", - returnType: "void", - params: [ - {type: "float", name: "scaleX"}, - {type: "float", name: "scaleY"} - ] - }, - { - name: "GetMouseWheelMove", - description: "Get mouse wheel movement for X or Y, whichever is larger", - returnType: "float" - }, - { - name: "GetMouseWheelMoveV", - description: "Get mouse wheel movement for both X and Y", - returnType: "Vector2" - }, - { - name: "SetMouseCursor", - description: "Set mouse cursor", - returnType: "void", - params: [ - {type: "int", name: "cursor"} - ] - }, - { - name: "GetTouchX", - description: "Get touch position X for touch point 0 (relative to screen size)", - returnType: "int" - }, - { - name: "GetTouchY", - description: "Get touch position Y for touch point 0 (relative to screen size)", - returnType: "int" - }, - { - name: "GetTouchPosition", - description: "Get touch position XY for a touch point index (relative to screen size)", - returnType: "Vector2", - params: [ - {type: "int", name: "index"} - ] - }, - { - name: "GetTouchPointId", - description: "Get touch point identifier for given index", - returnType: "int", - params: [ - {type: "int", name: "index"} - ] - }, - { - name: "GetTouchPointCount", - description: "Get number of touch points", - returnType: "int" - }, - { - name: "SetGesturesEnabled", - description: "Enable a set of gestures using flags", - returnType: "void", - params: [ - {type: "unsigned int", name: "flags"} - ] - }, - { - name: "IsGestureDetected", - description: "Check if gesture has been detected", - returnType: "bool", - params: [ - {type: "unsigned int", name: "gesture"} - ] - }, - { - name: "GetGestureDetected", - description: "Get latest detected gesture", - returnType: "int" - }, - { - name: "GetGestureHoldDuration", - description: "Get gesture hold time in seconds", - returnType: "float" - }, - { - name: "GetGestureDragVector", - description: "Get gesture drag vector", - returnType: "Vector2" - }, - { - name: "GetGestureDragAngle", - description: "Get gesture drag angle", - returnType: "float" - }, - { - name: "GetGesturePinchVector", - description: "Get gesture pinch delta", - returnType: "Vector2" - }, - { - name: "GetGesturePinchAngle", - description: "Get gesture pinch angle", - returnType: "float" - }, - { - name: "UpdateCamera", - description: "Update camera position for selected mode", - returnType: "void", - params: [ - {type: "Camera *", name: "camera"}, - {type: "int", name: "mode"} - ] - }, - { - name: "UpdateCameraPro", - description: "Update camera movement/rotation", - returnType: "void", - params: [ - {type: "Camera *", name: "camera"}, - {type: "Vector3", name: "movement"}, - {type: "Vector3", name: "rotation"}, - {type: "float", name: "zoom"} - ] - }, - { - name: "SetShapesTexture", - description: "Set texture and rectangle to be used on shapes drawing", - returnType: "void", - params: [ - {type: "Texture2D", name: "texture"}, - {type: "Rectangle", name: "rec"} - ] - }, - { - name: "GetShapesTexture", - description: "Get texture that is used for shapes drawing", - returnType: "Texture2D" - }, - { - name: "GetShapesTextureRectangle", - description: "Get texture source rectangle that is used for shapes drawing", - returnType: "Rectangle" - }, - { - name: "DrawPixel", - description: "Draw a pixel using geometry [Can be slow, use with care]", - returnType: "void", - params: [ - {type: "int", name: "posX"}, - {type: "int", name: "posY"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawPixelV", - description: "Draw a pixel using geometry (Vector version) [Can be slow, use with care]", - returnType: "void", - params: [ - {type: "Vector2", name: "position"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawLine", - description: "Draw a line", - returnType: "void", - params: [ - {type: "int", name: "startPosX"}, - {type: "int", name: "startPosY"}, - {type: "int", name: "endPosX"}, - {type: "int", name: "endPosY"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawLineV", - description: "Draw a line (using gl lines)", - returnType: "void", - params: [ - {type: "Vector2", name: "startPos"}, - {type: "Vector2", name: "endPos"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawLineEx", - description: "Draw a line (using triangles/quads)", - returnType: "void", - params: [ - {type: "Vector2", name: "startPos"}, - {type: "Vector2", name: "endPos"}, - {type: "float", name: "thick"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawLineStrip", - description: "Draw lines sequence (using gl lines)", - returnType: "void", - params: [ - {type: "const Vector2 *", name: "points"}, - {type: "int", name: "pointCount"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawLineBezier", - description: "Draw line segment cubic-bezier in-out interpolation", - returnType: "void", - params: [ - {type: "Vector2", name: "startPos"}, - {type: "Vector2", name: "endPos"}, - {type: "float", name: "thick"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawLineDashed", - description: "Draw a dashed line", - returnType: "void", - params: [ - {type: "Vector2", name: "startPos"}, - {type: "Vector2", name: "endPos"}, - {type: "int", name: "dashSize"}, - {type: "int", name: "spaceSize"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawCircle", - description: "Draw a color-filled circle", - returnType: "void", - params: [ - {type: "int", name: "centerX"}, - {type: "int", name: "centerY"}, - {type: "float", name: "radius"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawCircleV", - description: "Draw a color-filled circle (Vector version)", - returnType: "void", - params: [ - {type: "Vector2", name: "center"}, - {type: "float", name: "radius"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawCircleGradient", - description: "Draw a gradient-filled circle", - returnType: "void", - params: [ - {type: "Vector2", name: "center"}, - {type: "float", name: "radius"}, - {type: "Color", name: "inner"}, - {type: "Color", name: "outer"} - ] - }, - { - name: "DrawCircleSector", - description: "Draw a piece of a circle", - returnType: "void", - params: [ - {type: "Vector2", name: "center"}, - {type: "float", name: "radius"}, - {type: "float", name: "startAngle"}, - {type: "float", name: "endAngle"}, - {type: "int", name: "segments"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawCircleSectorLines", - description: "Draw circle sector outline", - returnType: "void", - params: [ - {type: "Vector2", name: "center"}, - {type: "float", name: "radius"}, - {type: "float", name: "startAngle"}, - {type: "float", name: "endAngle"}, - {type: "int", name: "segments"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawCircleLines", - description: "Draw circle outline", - returnType: "void", - params: [ - {type: "int", name: "centerX"}, - {type: "int", name: "centerY"}, - {type: "float", name: "radius"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawCircleLinesV", - description: "Draw circle outline (Vector version)", - returnType: "void", - params: [ - {type: "Vector2", name: "center"}, - {type: "float", name: "radius"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawEllipse", - description: "Draw ellipse", - returnType: "void", - params: [ - {type: "int", name: "centerX"}, - {type: "int", name: "centerY"}, - {type: "float", name: "radiusH"}, - {type: "float", name: "radiusV"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawEllipseV", - description: "Draw ellipse (Vector version)", - returnType: "void", - params: [ - {type: "Vector2", name: "center"}, - {type: "float", name: "radiusH"}, - {type: "float", name: "radiusV"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawEllipseLines", - description: "Draw ellipse outline", - returnType: "void", - params: [ - {type: "int", name: "centerX"}, - {type: "int", name: "centerY"}, - {type: "float", name: "radiusH"}, - {type: "float", name: "radiusV"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawEllipseLinesV", - description: "Draw ellipse outline (Vector version)", - returnType: "void", - params: [ - {type: "Vector2", name: "center"}, - {type: "float", name: "radiusH"}, - {type: "float", name: "radiusV"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawRing", - description: "Draw ring", - returnType: "void", - params: [ - {type: "Vector2", name: "center"}, - {type: "float", name: "innerRadius"}, - {type: "float", name: "outerRadius"}, - {type: "float", name: "startAngle"}, - {type: "float", name: "endAngle"}, - {type: "int", name: "segments"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawRingLines", - description: "Draw ring outline", - returnType: "void", - params: [ - {type: "Vector2", name: "center"}, - {type: "float", name: "innerRadius"}, - {type: "float", name: "outerRadius"}, - {type: "float", name: "startAngle"}, - {type: "float", name: "endAngle"}, - {type: "int", name: "segments"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawRectangle", - description: "Draw a color-filled rectangle", - returnType: "void", - params: [ - {type: "int", name: "posX"}, - {type: "int", name: "posY"}, - {type: "int", name: "width"}, - {type: "int", name: "height"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawRectangleV", - description: "Draw a color-filled rectangle (Vector version)", - returnType: "void", - params: [ - {type: "Vector2", name: "position"}, - {type: "Vector2", name: "size"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawRectangleRec", - description: "Draw a color-filled rectangle", - returnType: "void", - params: [ - {type: "Rectangle", name: "rec"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawRectanglePro", - description: "Draw a color-filled rectangle with pro parameters", - returnType: "void", - params: [ - {type: "Rectangle", name: "rec"}, - {type: "Vector2", name: "origin"}, - {type: "float", name: "rotation"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawRectangleGradientV", - description: "Draw a vertical-gradient-filled rectangle", - returnType: "void", - params: [ - {type: "int", name: "posX"}, - {type: "int", name: "posY"}, - {type: "int", name: "width"}, - {type: "int", name: "height"}, - {type: "Color", name: "top"}, - {type: "Color", name: "bottom"} - ] - }, - { - name: "DrawRectangleGradientH", - description: "Draw a horizontal-gradient-filled rectangle", - returnType: "void", - params: [ - {type: "int", name: "posX"}, - {type: "int", name: "posY"}, - {type: "int", name: "width"}, - {type: "int", name: "height"}, - {type: "Color", name: "left"}, - {type: "Color", name: "right"} - ] - }, - { - name: "DrawRectangleGradientEx", - description: "Draw a gradient-filled rectangle with custom vertex colors", - returnType: "void", - params: [ - {type: "Rectangle", name: "rec"}, - {type: "Color", name: "topLeft"}, - {type: "Color", name: "bottomLeft"}, - {type: "Color", name: "bottomRight"}, - {type: "Color", name: "topRight"} - ] - }, - { - name: "DrawRectangleLines", - description: "Draw rectangle outline", - returnType: "void", - params: [ - {type: "int", name: "posX"}, - {type: "int", name: "posY"}, - {type: "int", name: "width"}, - {type: "int", name: "height"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawRectangleLinesEx", - description: "Draw rectangle outline with extended parameters", - returnType: "void", - params: [ - {type: "Rectangle", name: "rec"}, - {type: "float", name: "lineThick"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawRectangleRounded", - description: "Draw rectangle with rounded edges", - returnType: "void", - params: [ - {type: "Rectangle", name: "rec"}, - {type: "float", name: "roundness"}, - {type: "int", name: "segments"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawRectangleRoundedLines", - description: "Draw rectangle lines with rounded edges", - returnType: "void", - params: [ - {type: "Rectangle", name: "rec"}, - {type: "float", name: "roundness"}, - {type: "int", name: "segments"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawRectangleRoundedLinesEx", - description: "Draw rectangle lines with rounded edges outline", - returnType: "void", - params: [ - {type: "Rectangle", name: "rec"}, - {type: "float", name: "roundness"}, - {type: "int", name: "segments"}, - {type: "float", name: "lineThick"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawTriangle", - description: "Draw a color-filled triangle (vertex in counter-clockwise order!)", - returnType: "void", - params: [ - {type: "Vector2", name: "v1"}, - {type: "Vector2", name: "v2"}, - {type: "Vector2", name: "v3"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawTriangleGradient", - description: "Draw triangle with interpolated colors (vertex in counter-clockwise order!)", - returnType: "void", - params: [ - {type: "Vector2", name: "v1"}, - {type: "Vector2", name: "v2"}, - {type: "Vector2", name: "v3"}, - {type: "Color", name: "c1"}, - {type: "Color", name: "c2"}, - {type: "Color", name: "c3"} - ] - }, - { - name: "DrawTriangleLines", - description: "Draw triangle outline (vertex in counter-clockwise order!)", - returnType: "void", - params: [ - {type: "Vector2", name: "v1"}, - {type: "Vector2", name: "v2"}, - {type: "Vector2", name: "v3"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawTriangleFan", - description: "Draw a triangle fan defined by points (first vertex is the center)", - returnType: "void", - params: [ - {type: "const Vector2 *", name: "points"}, - {type: "int", name: "pointCount"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawTriangleStrip", - description: "Draw a triangle strip defined by points", - returnType: "void", - params: [ - {type: "const Vector2 *", name: "points"}, - {type: "int", name: "pointCount"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawPoly", - description: "Draw a polygon of n sides", - returnType: "void", - params: [ - {type: "Vector2", name: "center"}, - {type: "int", name: "sides"}, - {type: "float", name: "radius"}, - {type: "float", name: "rotation"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawPolyLines", - description: "Draw a polygon outline of n sides", - returnType: "void", - params: [ - {type: "Vector2", name: "center"}, - {type: "int", name: "sides"}, - {type: "float", name: "radius"}, - {type: "float", name: "rotation"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawPolyLinesEx", - description: "Draw a polygon outline of n sides with extended parameters", - returnType: "void", - params: [ - {type: "Vector2", name: "center"}, - {type: "int", name: "sides"}, - {type: "float", name: "radius"}, - {type: "float", name: "rotation"}, - {type: "float", name: "lineThick"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawSplineLinear", - description: "Draw spline: Linear, minimum 2 points", - returnType: "void", - params: [ - {type: "const Vector2 *", name: "points"}, - {type: "int", name: "pointCount"}, - {type: "float", name: "thick"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawSplineBasis", - description: "Draw spline: B-Spline, minimum 4 points", - returnType: "void", - params: [ - {type: "const Vector2 *", name: "points"}, - {type: "int", name: "pointCount"}, - {type: "float", name: "thick"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawSplineCatmullRom", - description: "Draw spline: Catmull-Rom, minimum 4 points", - returnType: "void", - params: [ - {type: "const Vector2 *", name: "points"}, - {type: "int", name: "pointCount"}, - {type: "float", name: "thick"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawSplineBezierQuadratic", - description: "Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...]", - returnType: "void", - params: [ - {type: "const Vector2 *", name: "points"}, - {type: "int", name: "pointCount"}, - {type: "float", name: "thick"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawSplineBezierCubic", - description: "Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...]", - returnType: "void", - params: [ - {type: "const Vector2 *", name: "points"}, - {type: "int", name: "pointCount"}, - {type: "float", name: "thick"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawSplineSegmentLinear", - description: "Draw spline segment: Linear, 2 points", - returnType: "void", - params: [ - {type: "Vector2", name: "p1"}, - {type: "Vector2", name: "p2"}, - {type: "float", name: "thick"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawSplineSegmentBasis", - description: "Draw spline segment: B-Spline, 4 points", - returnType: "void", - params: [ - {type: "Vector2", name: "p1"}, - {type: "Vector2", name: "p2"}, - {type: "Vector2", name: "p3"}, - {type: "Vector2", name: "p4"}, - {type: "float", name: "thick"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawSplineSegmentCatmullRom", - description: "Draw spline segment: Catmull-Rom, 4 points", - returnType: "void", - params: [ - {type: "Vector2", name: "p1"}, - {type: "Vector2", name: "p2"}, - {type: "Vector2", name: "p3"}, - {type: "Vector2", name: "p4"}, - {type: "float", name: "thick"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawSplineSegmentBezierQuadratic", - description: "Draw spline segment: Quadratic Bezier, 2 points, 1 control point", - returnType: "void", - params: [ - {type: "Vector2", name: "p1"}, - {type: "Vector2", name: "c2"}, - {type: "Vector2", name: "p3"}, - {type: "float", name: "thick"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawSplineSegmentBezierCubic", - description: "Draw spline segment: Cubic Bezier, 2 points, 2 control points", - returnType: "void", - params: [ - {type: "Vector2", name: "p1"}, - {type: "Vector2", name: "c2"}, - {type: "Vector2", name: "c3"}, - {type: "Vector2", name: "p4"}, - {type: "float", name: "thick"}, - {type: "Color", name: "color"} - ] - }, - { - name: "GetSplinePointLinear", - description: "Get (evaluate) spline point: Linear", - returnType: "Vector2", - params: [ - {type: "Vector2", name: "startPos"}, - {type: "Vector2", name: "endPos"}, - {type: "float", name: "t"} - ] - }, - { - name: "GetSplinePointBasis", - description: "Get (evaluate) spline point: B-Spline", - returnType: "Vector2", - params: [ - {type: "Vector2", name: "p1"}, - {type: "Vector2", name: "p2"}, - {type: "Vector2", name: "p3"}, - {type: "Vector2", name: "p4"}, - {type: "float", name: "t"} - ] - }, - { - name: "GetSplinePointCatmullRom", - description: "Get (evaluate) spline point: Catmull-Rom", - returnType: "Vector2", - params: [ - {type: "Vector2", name: "p1"}, - {type: "Vector2", name: "p2"}, - {type: "Vector2", name: "p3"}, - {type: "Vector2", name: "p4"}, - {type: "float", name: "t"} - ] - }, - { - name: "GetSplinePointBezierQuadratic", - description: "Get (evaluate) spline point: Quadratic Bezier", - returnType: "Vector2", - params: [ - {type: "Vector2", name: "p1"}, - {type: "Vector2", name: "c2"}, - {type: "Vector2", name: "p3"}, - {type: "float", name: "t"} - ] - }, - { - name: "GetSplinePointBezierCubic", - description: "Get (evaluate) spline point: Cubic Bezier", - returnType: "Vector2", - params: [ - {type: "Vector2", name: "p1"}, - {type: "Vector2", name: "c2"}, - {type: "Vector2", name: "c3"}, - {type: "Vector2", name: "p4"}, - {type: "float", name: "t"} - ] - }, - { - name: "CheckCollisionRecs", - description: "Check collision between two rectangles", - returnType: "bool", - params: [ - {type: "Rectangle", name: "rec1"}, - {type: "Rectangle", name: "rec2"} - ] - }, - { - name: "CheckCollisionCircles", - description: "Check collision between two circles", - returnType: "bool", - params: [ - {type: "Vector2", name: "center1"}, - {type: "float", name: "radius1"}, - {type: "Vector2", name: "center2"}, - {type: "float", name: "radius2"} - ] - }, - { - name: "CheckCollisionCircleRec", - description: "Check collision between circle and rectangle", - returnType: "bool", - params: [ - {type: "Vector2", name: "center"}, - {type: "float", name: "radius"}, - {type: "Rectangle", name: "rec"} - ] - }, - { - name: "CheckCollisionCircleLine", - description: "Check if circle collides with a line created between two points [p1] and [p2]", - returnType: "bool", - params: [ - {type: "Vector2", name: "center"}, - {type: "float", name: "radius"}, - {type: "Vector2", name: "p1"}, - {type: "Vector2", name: "p2"} - ] - }, - { - name: "CheckCollisionPointRec", - description: "Check if point is inside rectangle", - returnType: "bool", - params: [ - {type: "Vector2", name: "point"}, - {type: "Rectangle", name: "rec"} - ] - }, - { - name: "CheckCollisionPointCircle", - description: "Check if point is inside circle", - returnType: "bool", - params: [ - {type: "Vector2", name: "point"}, - {type: "Vector2", name: "center"}, - {type: "float", name: "radius"} - ] - }, - { - name: "CheckCollisionPointTriangle", - description: "Check if point is inside a triangle", - returnType: "bool", - params: [ - {type: "Vector2", name: "point"}, - {type: "Vector2", name: "p1"}, - {type: "Vector2", name: "p2"}, - {type: "Vector2", name: "p3"} - ] - }, - { - name: "CheckCollisionPointLine", - description: "Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold]", - returnType: "bool", - params: [ - {type: "Vector2", name: "point"}, - {type: "Vector2", name: "p1"}, - {type: "Vector2", name: "p2"}, - {type: "int", name: "threshold"} - ] - }, - { - name: "CheckCollisionPointPoly", - description: "Check if point is within a polygon described by array of vertices", - returnType: "bool", - params: [ - {type: "Vector2", name: "point"}, - {type: "const Vector2 *", name: "points"}, - {type: "int", name: "pointCount"} - ] - }, - { - name: "CheckCollisionLines", - description: "Check the collision between two lines defined by two points each, returns collision point by reference", - returnType: "bool", - params: [ - {type: "Vector2", name: "startPos1"}, - {type: "Vector2", name: "endPos1"}, - {type: "Vector2", name: "startPos2"}, - {type: "Vector2", name: "endPos2"}, - {type: "Vector2 *", name: "collisionPoint"} - ] - }, - { - name: "GetCollisionRec", - description: "Get collision rectangle for two rectangles collision", - returnType: "Rectangle", - params: [ - {type: "Rectangle", name: "rec1"}, - {type: "Rectangle", name: "rec2"} - ] - }, - { - name: "LoadImage", - description: "Load image from file into CPU memory (RAM)", - returnType: "Image", - params: [ - {type: "const char *", name: "fileName"} - ] - }, - { - name: "LoadImageRaw", - description: "Load image from RAW file data", - returnType: "Image", - params: [ - {type: "const char *", name: "fileName"}, - {type: "int", name: "width"}, - {type: "int", name: "height"}, - {type: "int", name: "format"}, - {type: "int", name: "headerSize"} - ] - }, - { - name: "LoadImageAnim", - description: "Load image sequence from file (frames appended to image.data)", - returnType: "Image", - params: [ - {type: "const char *", name: "fileName"}, - {type: "int *", name: "frames"} - ] - }, - { - name: "LoadImageAnimFromMemory", - description: "Load image sequence from memory buffer", - returnType: "Image", - params: [ - {type: "const char *", name: "fileType"}, - {type: "const unsigned char *", name: "fileData"}, - {type: "int", name: "dataSize"}, - {type: "int *", name: "frames"} - ] - }, - { - name: "LoadImageFromMemory", - description: "Load image from memory buffer, fileType refers to extension: i.e. '.png'", - returnType: "Image", - params: [ - {type: "const char *", name: "fileType"}, - {type: "const unsigned char *", name: "fileData"}, - {type: "int", name: "dataSize"} - ] - }, - { - name: "LoadImageFromTexture", - description: "Load image from GPU texture data", - returnType: "Image", - params: [ - {type: "Texture2D", name: "texture"} - ] - }, - { - name: "LoadImageFromScreen", - description: "Load image from screen buffer (screenshot)", - returnType: "Image" - }, - { - name: "IsImageValid", - description: "Check if an image is valid (data and parameters)", - returnType: "bool", - params: [ - {type: "Image", name: "image"} - ] - }, - { - name: "UnloadImage", - description: "Unload image from CPU memory (RAM)", - returnType: "void", - params: [ - {type: "Image", name: "image"} - ] - }, - { - name: "ExportImage", - description: "Export image data to file, returns true on success", - returnType: "bool", - params: [ - {type: "Image", name: "image"}, - {type: "const char *", name: "fileName"} - ] - }, - { - name: "ExportImageToMemory", - description: "Export image to memory buffer, memory must be MemFree()", - returnType: "unsigned char *", - params: [ - {type: "Image", name: "image"}, - {type: "const char *", name: "fileType"}, - {type: "int *", name: "fileSize"} - ] - }, - { - name: "ExportImageAsCode", - description: "Export image as code file defining an array of bytes, returns true on success", - returnType: "bool", - params: [ - {type: "Image", name: "image"}, - {type: "const char *", name: "fileName"} - ] - }, - { - name: "GenImageColor", - description: "Generate image: plain color", - returnType: "Image", - params: [ - {type: "int", name: "width"}, - {type: "int", name: "height"}, - {type: "Color", name: "color"} - ] - }, - { - name: "GenImageGradientLinear", - description: "Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient", - returnType: "Image", - params: [ - {type: "int", name: "width"}, - {type: "int", name: "height"}, - {type: "int", name: "direction"}, - {type: "Color", name: "start"}, - {type: "Color", name: "end"} - ] - }, - { - name: "GenImageGradientRadial", - description: "Generate image: radial gradient", - returnType: "Image", - params: [ - {type: "int", name: "width"}, - {type: "int", name: "height"}, - {type: "float", name: "density"}, - {type: "Color", name: "inner"}, - {type: "Color", name: "outer"} - ] - }, - { - name: "GenImageGradientSquare", - description: "Generate image: square gradient", - returnType: "Image", - params: [ - {type: "int", name: "width"}, - {type: "int", name: "height"}, - {type: "float", name: "density"}, - {type: "Color", name: "inner"}, - {type: "Color", name: "outer"} - ] - }, - { - name: "GenImageChecked", - description: "Generate image: checked", - returnType: "Image", - params: [ - {type: "int", name: "width"}, - {type: "int", name: "height"}, - {type: "int", name: "checksX"}, - {type: "int", name: "checksY"}, - {type: "Color", name: "col1"}, - {type: "Color", name: "col2"} - ] - }, - { - name: "GenImageWhiteNoise", - description: "Generate image: white noise", - returnType: "Image", - params: [ - {type: "int", name: "width"}, - {type: "int", name: "height"}, - {type: "float", name: "factor"} - ] - }, - { - name: "GenImagePerlinNoise", - description: "Generate image: perlin noise", - returnType: "Image", - params: [ - {type: "int", name: "width"}, - {type: "int", name: "height"}, - {type: "int", name: "offsetX"}, - {type: "int", name: "offsetY"}, - {type: "float", name: "scale"} - ] - }, - { - name: "GenImageCellular", - description: "Generate image: cellular algorithm, bigger tileSize means bigger cells", - returnType: "Image", - params: [ - {type: "int", name: "width"}, - {type: "int", name: "height"}, - {type: "int", name: "tileSize"} - ] - }, - { - name: "GenImageText", - description: "Generate image: grayscale image from text data", - returnType: "Image", - params: [ - {type: "int", name: "width"}, - {type: "int", name: "height"}, - {type: "const char *", name: "text"} - ] - }, - { - name: "ImageCopy", - description: "Create an image duplicate (useful for transformations)", - returnType: "Image", - params: [ - {type: "Image", name: "image"} - ] - }, - { - name: "ImageFromImage", - description: "Create an image from another image piece", - returnType: "Image", - params: [ - {type: "Image", name: "image"}, - {type: "Rectangle", name: "rec"} - ] - }, - { - name: "ImageFromChannel", - description: "Create an image from a selected channel of another image (GRAYSCALE)", - returnType: "Image", - params: [ - {type: "Image", name: "image"}, - {type: "int", name: "selectedChannel"} - ] - }, - { - name: "ImageText", - description: "Create an image from text (default font)", - returnType: "Image", - params: [ - {type: "const char *", name: "text"}, - {type: "int", name: "fontSize"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageTextEx", - description: "Create an image from text (custom sprite font)", - returnType: "Image", - params: [ - {type: "Font", name: "font"}, - {type: "const char *", name: "text"}, - {type: "float", name: "fontSize"}, - {type: "float", name: "spacing"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "ImageFormat", - description: "Convert image data to desired format", - returnType: "void", - params: [ - {type: "Image *", name: "image"}, - {type: "int", name: "newFormat"} - ] - }, - { - name: "ImageToPOT", - description: "Convert image to POT (power-of-two)", - returnType: "void", - params: [ - {type: "Image *", name: "image"}, - {type: "Color", name: "fill"} - ] - }, - { - name: "ImageCrop", - description: "Crop an image to a defined rectangle", - returnType: "void", - params: [ - {type: "Image *", name: "image"}, - {type: "Rectangle", name: "crop"} - ] - }, - { - name: "ImageAlphaCrop", - description: "Crop image depending on alpha value", - returnType: "void", - params: [ - {type: "Image *", name: "image"}, - {type: "float", name: "threshold"} - ] - }, - { - name: "ImageAlphaClear", - description: "Clear alpha channel to desired color", - returnType: "void", - params: [ - {type: "Image *", name: "image"}, - {type: "Color", name: "color"}, - {type: "float", name: "threshold"} - ] - }, - { - name: "ImageAlphaMask", - description: "Apply alpha mask to image", - returnType: "void", - params: [ - {type: "Image *", name: "image"}, - {type: "Image", name: "alphaMask"} - ] - }, - { - name: "ImageAlphaPremultiply", - description: "Premultiply alpha channel", - returnType: "void", - params: [ - {type: "Image *", name: "image"} - ] - }, - { - name: "ImageBlurGaussian", - description: "Apply Gaussian blur using a box blur approximation", - returnType: "void", - params: [ - {type: "Image *", name: "image"}, - {type: "int", name: "blurSize"} - ] - }, - { - name: "ImageKernelConvolution", - description: "Apply custom square convolution kernel to image", - returnType: "void", - params: [ - {type: "Image *", name: "image"}, - {type: "const float *", name: "kernel"}, - {type: "int", name: "kernelSize"} - ] - }, - { - name: "ImageResize", - description: "Resize image (Bicubic scaling algorithm)", - returnType: "void", - params: [ - {type: "Image *", name: "image"}, - {type: "int", name: "newWidth"}, - {type: "int", name: "newHeight"} - ] - }, - { - name: "ImageResizeNN", - description: "Resize image (Nearest-Neighbor scaling algorithm)", - returnType: "void", - params: [ - {type: "Image *", name: "image"}, - {type: "int", name: "newWidth"}, - {type: "int", name: "newHeight"} - ] - }, - { - name: "ImageResizeCanvas", - description: "Resize canvas and fill with color", - returnType: "void", - params: [ - {type: "Image *", name: "image"}, - {type: "int", name: "newWidth"}, - {type: "int", name: "newHeight"}, - {type: "int", name: "offsetX"}, - {type: "int", name: "offsetY"}, - {type: "Color", name: "fill"} - ] - }, - { - name: "ImageMipmaps", - description: "Compute all mipmap levels for a provided image", - returnType: "void", - params: [ - {type: "Image *", name: "image"} - ] - }, - { - name: "ImageDither", - description: "Dither image data to 16bpp or lower (Floyd-Steinberg dithering)", - returnType: "void", - params: [ - {type: "Image *", name: "image"}, - {type: "int", name: "rBpp"}, - {type: "int", name: "gBpp"}, - {type: "int", name: "bBpp"}, - {type: "int", name: "aBpp"} - ] - }, - { - name: "ImageFlipVertical", - description: "Flip image vertically", - returnType: "void", - params: [ - {type: "Image *", name: "image"} - ] - }, - { - name: "ImageFlipHorizontal", - description: "Flip image horizontally", - returnType: "void", - params: [ - {type: "Image *", name: "image"} - ] - }, - { - name: "ImageRotate", - description: "Rotate image by input angle in degrees (-359 to 359)", - returnType: "void", - params: [ - {type: "Image *", name: "image"}, - {type: "int", name: "degrees"} - ] - }, - { - name: "ImageRotateCW", - description: "Rotate image clockwise 90deg", - returnType: "void", - params: [ - {type: "Image *", name: "image"} - ] - }, - { - name: "ImageRotateCCW", - description: "Rotate image counter-clockwise 90deg", - returnType: "void", - params: [ - {type: "Image *", name: "image"} - ] - }, - { - name: "ImageColorTint", - description: "Modify image color: tint", - returnType: "void", - params: [ - {type: "Image *", name: "image"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageColorInvert", - description: "Modify image color: invert", - returnType: "void", - params: [ - {type: "Image *", name: "image"} - ] - }, - { - name: "ImageColorGrayscale", - description: "Modify image color: grayscale", - returnType: "void", - params: [ - {type: "Image *", name: "image"} - ] - }, - { - name: "ImageColorContrast", - description: "Modify image color: contrast (-100 to 100)", - returnType: "void", - params: [ - {type: "Image *", name: "image"}, - {type: "int", name: "contrast"} - ] - }, - { - name: "ImageColorBrightness", - description: "Modify image color: brightness (-255 to 255)", - returnType: "void", - params: [ - {type: "Image *", name: "image"}, - {type: "int", name: "brightness"} - ] - }, - { - name: "ImageColorReplace", - description: "Modify image color: replace color", - returnType: "void", - params: [ - {type: "Image *", name: "image"}, - {type: "Color", name: "color"}, - {type: "Color", name: "replace"} - ] - }, - { - name: "LoadImageColors", - description: "Load color data from image as a Color array (RGBA - 32bit)", - returnType: "Color *", - params: [ - {type: "Image", name: "image"} - ] - }, - { - name: "LoadImagePalette", - description: "Load colors palette from image as a Color array (RGBA - 32bit)", - returnType: "Color *", - params: [ - {type: "Image", name: "image"}, - {type: "int", name: "maxPaletteSize"}, - {type: "int *", name: "colorCount"} - ] - }, - { - name: "UnloadImageColors", - description: "Unload color data loaded with LoadImageColors()", - returnType: "void", - params: [ - {type: "Color *", name: "colors"} - ] - }, - { - name: "UnloadImagePalette", - description: "Unload colors palette loaded with LoadImagePalette()", - returnType: "void", - params: [ - {type: "Color *", name: "colors"} - ] - }, - { - name: "GetImageAlphaBorder", - description: "Get image alpha border rectangle", - returnType: "Rectangle", - params: [ - {type: "Image", name: "image"}, - {type: "float", name: "threshold"} - ] - }, - { - name: "GetImageColor", - description: "Get image pixel color at (x, y) position", - returnType: "Color", - params: [ - {type: "Image", name: "image"}, - {type: "int", name: "x"}, - {type: "int", name: "y"} - ] - }, - { - name: "ImageClearBackground", - description: "Clear image background with given color", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageDrawPixel", - description: "Draw pixel within an image", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "int", name: "posX"}, - {type: "int", name: "posY"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageDrawPixelV", - description: "Draw pixel within an image (Vector version)", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "Vector2", name: "position"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageDrawLine", - description: "Draw line within an image", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "int", name: "startPosX"}, - {type: "int", name: "startPosY"}, - {type: "int", name: "endPosX"}, - {type: "int", name: "endPosY"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageDrawLineV", - description: "Draw line within an image (Vector version)", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "Vector2", name: "start"}, - {type: "Vector2", name: "end"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageDrawLineEx", - description: "Draw a line defining thickness within an image", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "Vector2", name: "start"}, - {type: "Vector2", name: "end"}, - {type: "int", name: "thick"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageDrawCircle", - description: "Draw a filled circle within an image", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "int", name: "centerX"}, - {type: "int", name: "centerY"}, - {type: "int", name: "radius"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageDrawCircleV", - description: "Draw a filled circle within an image (Vector version)", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "Vector2", name: "center"}, - {type: "int", name: "radius"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageDrawCircleLines", - description: "Draw circle outline within an image", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "int", name: "centerX"}, - {type: "int", name: "centerY"}, - {type: "int", name: "radius"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageDrawCircleLinesV", - description: "Draw circle outline within an image (Vector version)", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "Vector2", name: "center"}, - {type: "int", name: "radius"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageDrawRectangle", - description: "Draw rectangle within an image", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "int", name: "posX"}, - {type: "int", name: "posY"}, - {type: "int", name: "width"}, - {type: "int", name: "height"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageDrawRectangleV", - description: "Draw rectangle within an image (Vector version)", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "Vector2", name: "position"}, - {type: "Vector2", name: "size"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageDrawRectangleRec", - description: "Draw rectangle within an image", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "Rectangle", name: "rec"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageDrawRectangleLines", - description: "Draw rectangle lines within an image", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "int", name: "posX"}, - {type: "int", name: "posY"}, - {type: "int", name: "width"}, - {type: "int", name: "height"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageDrawRectangleLinesEx", - description: "Draw rectangle lines within an image with extended parameters", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "Rectangle", name: "rec"}, - {type: "int", name: "thick"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageDrawTriangle", - description: "Draw triangle within an image", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "Vector2", name: "v1"}, - {type: "Vector2", name: "v2"}, - {type: "Vector2", name: "v3"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageDrawTriangleGradient", - description: "Draw triangle with interpolated colors within an image", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "Vector2", name: "v1"}, - {type: "Vector2", name: "v2"}, - {type: "Vector2", name: "v3"}, - {type: "Color", name: "c1"}, - {type: "Color", name: "c2"}, - {type: "Color", name: "c3"} - ] - }, - { - name: "ImageDrawTriangleLines", - description: "Draw triangle outline within an image", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "Vector2", name: "v1"}, - {type: "Vector2", name: "v2"}, - {type: "Vector2", name: "v3"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageDrawTriangleFan", - description: "Draw a triangle fan defined by points within an image (first vertex is the center)", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "const Vector2 *", name: "points"}, - {type: "int", name: "pointCount"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageDrawTriangleStrip", - description: "Draw a triangle strip defined by points within an image", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "const Vector2 *", name: "points"}, - {type: "int", name: "pointCount"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageDraw", - description: "Draw a source image within a destination image (tint applied to source)", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "Image", name: "src"}, - {type: "Rectangle", name: "srcRec"}, - {type: "Rectangle", name: "dstRec"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "ImageDrawText", - description: "Draw text (using default font) within an image (destination)", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "const char *", name: "text"}, - {type: "int", name: "posX"}, - {type: "int", name: "posY"}, - {type: "int", name: "fontSize"}, - {type: "Color", name: "color"} - ] - }, - { - name: "ImageDrawTextEx", - description: "Draw text (custom sprite font) within an image (destination)", - returnType: "void", - params: [ - {type: "Image *", name: "dst"}, - {type: "Font", name: "font"}, - {type: "const char *", name: "text"}, - {type: "Vector2", name: "position"}, - {type: "float", name: "fontSize"}, - {type: "float", name: "spacing"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "LoadTexture", - description: "Load texture from file into GPU memory (VRAM)", - returnType: "Texture2D", - params: [ - {type: "const char *", name: "fileName"} - ] - }, - { - name: "LoadTextureFromImage", - description: "Load texture from image data", - returnType: "Texture2D", - params: [ - {type: "Image", name: "image"} - ] - }, - { - name: "LoadTextureCubemap", - description: "Load cubemap from image, multiple image cubemap layouts supported", - returnType: "TextureCubemap", - params: [ - {type: "Image", name: "image"}, - {type: "int", name: "layout"} - ] - }, - { - name: "LoadRenderTexture", - description: "Load texture for rendering (framebuffer)", - returnType: "RenderTexture2D", - params: [ - {type: "int", name: "width"}, - {type: "int", name: "height"} - ] - }, - { - name: "IsTextureValid", - description: "Check if texture is valid (loaded in GPU)", - returnType: "bool", - params: [ - {type: "Texture2D", name: "texture"} - ] - }, - { - name: "UnloadTexture", - description: "Unload texture from GPU memory (VRAM)", - returnType: "void", - params: [ - {type: "Texture2D", name: "texture"} - ] - }, - { - name: "IsRenderTextureValid", - description: "Check if render texture is valid (loaded in GPU)", - returnType: "bool", - params: [ - {type: "RenderTexture2D", name: "target"} - ] - }, - { - name: "UnloadRenderTexture", - description: "Unload render texture from GPU memory (VRAM)", - returnType: "void", - params: [ - {type: "RenderTexture2D", name: "target"} - ] - }, - { - name: "UpdateTexture", - description: "Update GPU texture with new data (pixels should be able to fill texture)", - returnType: "void", - params: [ - {type: "Texture2D", name: "texture"}, - {type: "const void *", name: "pixels"} - ] - }, - { - name: "UpdateTextureRec", - description: "Update GPU texture rectangle with new data (pixels and rec should fit in texture)", - returnType: "void", - params: [ - {type: "Texture2D", name: "texture"}, - {type: "Rectangle", name: "rec"}, - {type: "const void *", name: "pixels"} - ] - }, - { - name: "GenTextureMipmaps", - description: "Generate GPU mipmaps for a texture", - returnType: "void", - params: [ - {type: "Texture2D *", name: "texture"} - ] - }, - { - name: "SetTextureFilter", - description: "Set texture scaling filter mode", - returnType: "void", - params: [ - {type: "Texture2D", name: "texture"}, - {type: "int", name: "filter"} - ] - }, - { - name: "SetTextureWrap", - description: "Set texture wrapping mode", - returnType: "void", - params: [ - {type: "Texture2D", name: "texture"}, - {type: "int", name: "wrap"} - ] - }, - { - name: "DrawTexture", - description: "Draw a Texture2D", - returnType: "void", - params: [ - {type: "Texture2D", name: "texture"}, - {type: "int", name: "posX"}, - {type: "int", name: "posY"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "DrawTextureV", - description: "Draw a Texture2D with position defined as Vector2", - returnType: "void", - params: [ - {type: "Texture2D", name: "texture"}, - {type: "Vector2", name: "position"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "DrawTextureEx", - description: "Draw a Texture2D with extended parameters", - returnType: "void", - params: [ - {type: "Texture2D", name: "texture"}, - {type: "Vector2", name: "position"}, - {type: "float", name: "rotation"}, - {type: "float", name: "scale"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "DrawTextureRec", - description: "Draw a part of a texture defined by a rectangle", - returnType: "void", - params: [ - {type: "Texture2D", name: "texture"}, - {type: "Rectangle", name: "rec"}, - {type: "Vector2", name: "position"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "DrawTexturePro", - description: "Draw a part of a texture defined by a source rectangle to destination rectangle, with scaling and rotation", - returnType: "void", - params: [ - {type: "Texture2D", name: "texture"}, - {type: "Rectangle", name: "srcrec"}, - {type: "Rectangle", name: "dstrec"}, - {type: "Vector2", name: "origin"}, - {type: "float", name: "rotation"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "DrawTextureNPatch", - description: "Draw a texture (or part of it) that stretches or shrinks nicely", - returnType: "void", - params: [ - {type: "Texture2D", name: "texture"}, - {type: "NPatchInfo", name: "nPatchInfo"}, - {type: "Rectangle", name: "dstrec"}, - {type: "Vector2", name: "origin"}, - {type: "float", name: "rotation"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "ColorIsEqual", - description: "Check if two colors are equal", - returnType: "bool", - params: [ - {type: "Color", name: "col1"}, - {type: "Color", name: "col2"} - ] - }, - { - name: "Fade", - description: "Get color with alpha applied, alpha goes from 0.0f to 1.0f", - returnType: "Color", - params: [ - {type: "Color", name: "color"}, - {type: "float", name: "alpha"} - ] - }, - { - name: "ColorToInt", - description: "Get hexadecimal value for a Color (0xRRGGBBAA)", - returnType: "int", - params: [ - {type: "Color", name: "color"} - ] - }, - { - name: "ColorNormalize", - description: "Get Color normalized as float [0..1]", - returnType: "Vector4", - params: [ - {type: "Color", name: "color"} - ] - }, - { - name: "ColorFromNormalized", - description: "Get Color from normalized values [0..1]", - returnType: "Color", - params: [ - {type: "Vector4", name: "normalized"} - ] - }, - { - name: "ColorToHSV", - description: "Get HSV values for a Color, hue [0..360], saturation/value [0..1]", - returnType: "Vector3", - params: [ - {type: "Color", name: "color"} - ] - }, - { - name: "ColorFromHSV", - description: "Get a Color from HSV values, hue [0..360], saturation/value [0..1]", - returnType: "Color", - params: [ - {type: "float", name: "hue"}, - {type: "float", name: "saturation"}, - {type: "float", name: "value"} - ] - }, - { - name: "ColorTint", - description: "Get color multiplied with another color", - returnType: "Color", - params: [ - {type: "Color", name: "color"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "ColorBrightness", - description: "Get color with brightness correction, brightness factor goes from -1.0f to 1.0f", - returnType: "Color", - params: [ - {type: "Color", name: "color"}, - {type: "float", name: "factor"} - ] - }, - { - name: "ColorContrast", - description: "Get color with contrast correction, contrast values between -1.0f and 1.0f", - returnType: "Color", - params: [ - {type: "Color", name: "color"}, - {type: "float", name: "contrast"} - ] - }, - { - name: "ColorAlpha", - description: "Get color with alpha applied, alpha goes from 0.0f to 1.0f", - returnType: "Color", - params: [ - {type: "Color", name: "color"}, - {type: "float", name: "alpha"} - ] - }, - { - name: "ColorAlphaBlend", - description: "Get src alpha-blended into dst color with tint", - returnType: "Color", - params: [ - {type: "Color", name: "dst"}, - {type: "Color", name: "src"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "ColorLerp", - description: "Get color lerp interpolation between two colors, factor [0.0f..1.0f]", - returnType: "Color", - params: [ - {type: "Color", name: "color1"}, - {type: "Color", name: "color2"}, - {type: "float", name: "factor"} - ] - }, - { - name: "GetColor", - description: "Get Color structure from hexadecimal value", - returnType: "Color", - params: [ - {type: "unsigned int", name: "hexValue"} - ] - }, - { - name: "GetPixelColor", - description: "Get Color from a source pixel pointer of certain format", - returnType: "Color", - params: [ - {type: "const void *", name: "srcPtr"}, - {type: "int", name: "format"} - ] - }, - { - name: "SetPixelColor", - description: "Set color formatted into destination pixel pointer", - returnType: "void", - params: [ - {type: "void *", name: "dstPtr"}, - {type: "Color", name: "color"}, - {type: "int", name: "format"} - ] - }, - { - name: "GetPixelDataSize", - description: "Get pixel data size in bytes for certain format", - returnType: "int", - params: [ - {type: "int", name: "width"}, - {type: "int", name: "height"}, - {type: "int", name: "format"} - ] - }, - { - name: "GetFontDefault", - description: "Get the default Font", - returnType: "Font" - }, - { - name: "LoadFont", - description: "Load font from file into GPU memory (VRAM)", - returnType: "Font", - params: [ - {type: "const char *", name: "fileName"} - ] - }, - { - name: "LoadFontEx", - description: "Load font from file with extended parameters, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height", - returnType: "Font", - params: [ - {type: "const char *", name: "fileName"}, - {type: "int", name: "fontSize"}, - {type: "const int *", name: "codepoints"}, - {type: "int", name: "codepointCount"} - ] - }, - { - name: "LoadFontFromImage", - description: "Load font from Image (XNA style)", - returnType: "Font", - params: [ - {type: "Image", name: "image"}, - {type: "Color", name: "key"}, - {type: "int", name: "firstChar"} - ] - }, - { - name: "LoadFontFromMemory", - description: "Load font from memory buffer, fileType refers to extension: i.e. '.ttf'", - returnType: "Font", - params: [ - {type: "const char *", name: "fileType"}, - {type: "const unsigned char *", name: "fileData"}, - {type: "int", name: "dataSize"}, - {type: "int", name: "fontSize"}, - {type: "const int *", name: "codepoints"}, - {type: "int", name: "codepointCount"} - ] - }, - { - name: "IsFontValid", - description: "Check if font is valid (font data loaded, WARNING: GPU texture not checked)", - returnType: "bool", - params: [ - {type: "Font", name: "font"} - ] - }, - { - name: "LoadFontData", - description: "Load font data for further use", - returnType: "GlyphInfo *", - params: [ - {type: "const unsigned char *", name: "fileData"}, - {type: "int", name: "dataSize"}, - {type: "int", name: "fontSize"}, - {type: "const int *", name: "codepoints"}, - {type: "int", name: "codepointCount"}, - {type: "int", name: "type"}, - {type: "int *", name: "glyphCount"} - ] - }, - { - name: "GenImageFontAtlas", - description: "Generate image font atlas using chars info", - returnType: "Image", - params: [ - {type: "const GlyphInfo *", name: "glyphs"}, - {type: "Rectangle **", name: "glyphRecs"}, - {type: "int", name: "glyphCount"}, - {type: "int", name: "fontSize"}, - {type: "int", name: "padding"}, - {type: "int", name: "packMethod"} - ] - }, - { - name: "UnloadFontData", - description: "Unload font chars info data (RAM)", - returnType: "void", - params: [ - {type: "GlyphInfo *", name: "glyphs"}, - {type: "int", name: "glyphCount"} - ] - }, - { - name: "UnloadFont", - description: "Unload font from GPU memory (VRAM)", - returnType: "void", - params: [ - {type: "Font", name: "font"} - ] - }, - { - name: "ExportFontAsCode", - description: "Export font as code file, returns true on success", - returnType: "bool", - params: [ - {type: "Font", name: "font"}, - {type: "const char *", name: "fileName"} - ] - }, - { - name: "DrawFPS", - description: "Draw current FPS", - returnType: "void", - params: [ - {type: "int", name: "posX"}, - {type: "int", name: "posY"} - ] - }, - { - name: "DrawText", - description: "Draw text (using default font)", - returnType: "void", - params: [ - {type: "const char *", name: "text"}, - {type: "int", name: "posX"}, - {type: "int", name: "posY"}, - {type: "int", name: "fontSize"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawTextEx", - description: "Draw text using font and additional parameters", - returnType: "void", - params: [ - {type: "Font", name: "font"}, - {type: "const char *", name: "text"}, - {type: "Vector2", name: "position"}, - {type: "float", name: "fontSize"}, - {type: "float", name: "spacing"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "DrawTextPro", - description: "Draw text using Font and pro parameters (rotation)", - returnType: "void", - params: [ - {type: "Font", name: "font"}, - {type: "const char *", name: "text"}, - {type: "Vector2", name: "position"}, - {type: "Vector2", name: "origin"}, - {type: "float", name: "rotation"}, - {type: "float", name: "fontSize"}, - {type: "float", name: "spacing"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "DrawTextCodepoint", - description: "Draw one character (codepoint)", - returnType: "void", - params: [ - {type: "Font", name: "font"}, - {type: "int", name: "codepoint"}, - {type: "Vector2", name: "position"}, - {type: "float", name: "fontSize"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "DrawTextCodepoints", - description: "Draw multiple characters (codepoint)", - returnType: "void", - params: [ - {type: "Font", name: "font"}, - {type: "const int *", name: "codepoints"}, - {type: "int", name: "codepointCount"}, - {type: "Vector2", name: "position"}, - {type: "float", name: "fontSize"}, - {type: "float", name: "spacing"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "SetTextLineSpacing", - description: "Set vertical line spacing when drawing with line-breaks", - returnType: "void", - params: [ - {type: "int", name: "spacing"} - ] - }, - { - name: "MeasureText", - description: "Measure string width for default font", - returnType: "int", - params: [ - {type: "const char *", name: "text"}, - {type: "int", name: "fontSize"} - ] - }, - { - name: "MeasureTextEx", - description: "Measure string size for Font", - returnType: "Vector2", - params: [ - {type: "Font", name: "font"}, - {type: "const char *", name: "text"}, - {type: "float", name: "fontSize"}, - {type: "float", name: "spacing"} - ] - }, - { - name: "MeasureTextCodepoints", - description: "Measure string size for an existing array of codepoints for Font", - returnType: "Vector2", - params: [ - {type: "Font", name: "font"}, - {type: "const int *", name: "codepoints"}, - {type: "int", name: "length"}, - {type: "float", name: "fontSize"}, - {type: "float", name: "spacing"} - ] - }, - { - name: "GetGlyphIndex", - description: "Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found", - returnType: "int", - params: [ - {type: "Font", name: "font"}, - {type: "int", name: "codepoint"} - ] - }, - { - name: "GetGlyphInfo", - description: "Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found", - returnType: "GlyphInfo", - params: [ - {type: "Font", name: "font"}, - {type: "int", name: "codepoint"} - ] - }, - { - name: "GetGlyphAtlasRec", - description: "Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found", - returnType: "Rectangle", - params: [ - {type: "Font", name: "font"}, - {type: "int", name: "codepoint"} - ] - }, - { - name: "LoadUTF8", - description: "Load UTF-8 text encoded from codepoints array", - returnType: "char *", - params: [ - {type: "const int *", name: "codepoints"}, - {type: "int", name: "length"} - ] - }, - { - name: "UnloadUTF8", - description: "Unload UTF-8 text encoded from codepoints array", - returnType: "void", - params: [ - {type: "char *", name: "text"} - ] - }, - { - name: "LoadCodepoints", - description: "Load all codepoints from a UTF-8 text string, codepoints count returned by parameter", - returnType: "int *", - params: [ - {type: "const char *", name: "text"}, - {type: "int *", name: "count"} - ] - }, - { - name: "UnloadCodepoints", - description: "Unload codepoints data from memory", - returnType: "void", - params: [ - {type: "int *", name: "codepoints"} - ] - }, - { - name: "GetCodepointCount", - description: "Get total number of codepoints in a UTF-8 encoded string", - returnType: "int", - params: [ - {type: "const char *", name: "text"} - ] - }, - { - name: "GetCodepoint", - description: "Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure", - returnType: "int", - params: [ - {type: "const char *", name: "text"}, - {type: "int *", name: "codepointSize"} - ] - }, - { - name: "GetCodepointNext", - description: "Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure", - returnType: "int", - params: [ - {type: "const char *", name: "text"}, - {type: "int *", name: "codepointSize"} - ] - }, - { - name: "GetCodepointPrevious", - description: "Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure", - returnType: "int", - params: [ - {type: "const char *", name: "text"}, - {type: "int *", name: "codepointSize"} - ] - }, - { - name: "CodepointToUTF8", - description: "Encode one codepoint into UTF-8 byte array (array length returned as parameter)", - returnType: "const char *", - params: [ - {type: "int", name: "codepoint"}, - {type: "int *", name: "utf8Size"} - ] - }, - { - name: "LoadTextLines", - description: "Load text as separate lines ('\\n')", - returnType: "char **", - params: [ - {type: "const char *", name: "text"}, - {type: "int *", name: "count"} - ] - }, - { - name: "UnloadTextLines", - description: "Unload text lines", - returnType: "void", - params: [ - {type: "char **", name: "text"}, - {type: "int", name: "lineCount"} - ] - }, - { - name: "TextCopy", - description: "Copy one string to another, returns bytes copied", - returnType: "int", - params: [ - {type: "char *", name: "dst"}, - {type: "const char *", name: "src"} - ] - }, - { - name: "TextIsEqual", - description: "Check if two text strings are equal", - returnType: "bool", - params: [ - {type: "const char *", name: "text1"}, - {type: "const char *", name: "text2"} - ] - }, - { - name: "TextLength", - description: "Get text length, checks for '\\0' ending", - returnType: "unsigned int", - params: [ - {type: "const char *", name: "text"} - ] - }, - { - name: "TextFormat", - description: "Text formatting with variables (sprintf() style)", - returnType: "const char *", - params: [ - {type: "const char *", name: "text"}, - {type: "...", name: "args"} - ] - }, - { - name: "TextSubtext", - description: "Get a piece of a text string", - returnType: "const char *", - params: [ - {type: "const char *", name: "text"}, - {type: "int", name: "position"}, - {type: "int", name: "length"} - ] - }, - { - name: "TextRemoveSpaces", - description: "Remove text spaces, concat words", - returnType: "const char *", - params: [ - {type: "const char *", name: "text"} - ] - }, - { - name: "GetTextBetween", - description: "Get text between two strings", - returnType: "char *", - params: [ - {type: "const char *", name: "text"}, - {type: "const char *", name: "begin"}, - {type: "const char *", name: "end"} - ] - }, - { - name: "TextReplace", - description: "Replace text string with new string", - returnType: "char *", - params: [ - {type: "const char *", name: "text"}, - {type: "const char *", name: "search"}, - {type: "const char *", name: "replacement"} - ] - }, - { - name: "TextReplaceAlloc", - description: "Replace text string with new string, memory must be MemFree()", - returnType: "char *", - params: [ - {type: "const char *", name: "text"}, - {type: "const char *", name: "search"}, - {type: "const char *", name: "replacement"} - ] - }, - { - name: "TextReplaceBetween", - description: "Replace text between two specific strings", - returnType: "char *", - params: [ - {type: "const char *", name: "text"}, - {type: "const char *", name: "begin"}, - {type: "const char *", name: "end"}, - {type: "const char *", name: "replacement"} - ] - }, - { - name: "TextReplaceBetweenAlloc", - description: "Replace text between two specific strings, memory must be MemFree()", - returnType: "char *", - params: [ - {type: "const char *", name: "text"}, - {type: "const char *", name: "begin"}, - {type: "const char *", name: "end"}, - {type: "const char *", name: "replacement"} - ] - }, - { - name: "TextInsert", - description: "Insert text in a defined byte position", - returnType: "char *", - params: [ - {type: "const char *", name: "text"}, - {type: "const char *", name: "insert"}, - {type: "int", name: "position"} - ] - }, - { - name: "TextInsertAlloc", - description: "Insert text in a defined byte position, memory must be MemFree()", - returnType: "char *", - params: [ - {type: "const char *", name: "text"}, - {type: "const char *", name: "insert"}, - {type: "int", name: "position"} - ] - }, - { - name: "TextJoin", - description: "Join text strings with delimiter", - returnType: "char *", - params: [ - {type: "char **", name: "textList"}, - {type: "int", name: "count"}, - {type: "const char *", name: "delimiter"} - ] - }, - { - name: "TextSplit", - description: "Split text into multiple strings, using MAX_TEXTSPLIT_COUNT static strings", - returnType: "char **", - params: [ - {type: "const char *", name: "text"}, - {type: "char", name: "delimiter"}, - {type: "int *", name: "count"} - ] - }, - { - name: "TextAppend", - description: "Append text at specific position and move cursor", - returnType: "void", - params: [ - {type: "char *", name: "text"}, - {type: "const char *", name: "append"}, - {type: "int *", name: "position"} - ] - }, - { - name: "TextFindIndex", - description: "Find first text occurrence within a string, -1 if not found", - returnType: "int", - params: [ - {type: "const char *", name: "text"}, - {type: "const char *", name: "search"} - ] - }, - { - name: "TextToUpper", - description: "Get upper case version of provided string", - returnType: "char *", - params: [ - {type: "const char *", name: "text"} - ] - }, - { - name: "TextToLower", - description: "Get lower case version of provided string", - returnType: "char *", - params: [ - {type: "const char *", name: "text"} - ] - }, - { - name: "TextToPascal", - description: "Get Pascal case notation version of provided string", - returnType: "char *", - params: [ - {type: "const char *", name: "text"} - ] - }, - { - name: "TextToSnake", - description: "Get Snake case notation version of provided string", - returnType: "char *", - params: [ - {type: "const char *", name: "text"} - ] - }, - { - name: "TextToCamel", - description: "Get Camel case notation version of provided string", - returnType: "char *", - params: [ - {type: "const char *", name: "text"} - ] - }, - { - name: "TextToInteger", - description: "Get integer value from text", - returnType: "int", - params: [ - {type: "const char *", name: "text"} - ] - }, - { - name: "TextToFloat", - description: "Get float value from text", - returnType: "float", - params: [ - {type: "const char *", name: "text"} - ] - }, - { - name: "DrawLine3D", - description: "Draw a line in 3D world space", - returnType: "void", - params: [ - {type: "Vector3", name: "startPos"}, - {type: "Vector3", name: "endPos"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawPoint3D", - description: "Draw a point in 3D space, actually a small line", - returnType: "void", - params: [ - {type: "Vector3", name: "position"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawCircle3D", - description: "Draw a circle in 3D world space", - returnType: "void", - params: [ - {type: "Vector3", name: "center"}, - {type: "float", name: "radius"}, - {type: "Vector3", name: "rotationAxis"}, - {type: "float", name: "rotationAngle"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawTriangle3D", - description: "Draw a color-filled triangle (vertex in counter-clockwise order!)", - returnType: "void", - params: [ - {type: "Vector3", name: "v1"}, - {type: "Vector3", name: "v2"}, - {type: "Vector3", name: "v3"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawTriangleStrip3D", - description: "Draw a triangle strip defined by points", - returnType: "void", - params: [ - {type: "const Vector3 *", name: "points"}, - {type: "int", name: "pointCount"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawCube", - description: "Draw cube", - returnType: "void", - params: [ - {type: "Vector3", name: "position"}, - {type: "float", name: "width"}, - {type: "float", name: "height"}, - {type: "float", name: "length"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawCubeV", - description: "Draw cube (Vector version)", - returnType: "void", - params: [ - {type: "Vector3", name: "position"}, - {type: "Vector3", name: "size"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawCubeWires", - description: "Draw cube wires", - returnType: "void", - params: [ - {type: "Vector3", name: "position"}, - {type: "float", name: "width"}, - {type: "float", name: "height"}, - {type: "float", name: "length"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawCubeWiresV", - description: "Draw cube wires (Vector version)", - returnType: "void", - params: [ - {type: "Vector3", name: "position"}, - {type: "Vector3", name: "size"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawSphere", - description: "Draw sphere", - returnType: "void", - params: [ - {type: "Vector3", name: "centerPos"}, - {type: "float", name: "radius"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawSphereEx", - description: "Draw sphere with extended parameters", - returnType: "void", - params: [ - {type: "Vector3", name: "centerPos"}, - {type: "float", name: "radius"}, - {type: "int", name: "rings"}, - {type: "int", name: "slices"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawSphereWires", - description: "Draw sphere wires", - returnType: "void", - params: [ - {type: "Vector3", name: "centerPos"}, - {type: "float", name: "radius"}, - {type: "int", name: "rings"}, - {type: "int", name: "slices"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawCylinder", - description: "Draw a cylinder/cone", - returnType: "void", - params: [ - {type: "Vector3", name: "position"}, - {type: "float", name: "radiusTop"}, - {type: "float", name: "radiusBottom"}, - {type: "float", name: "height"}, - {type: "int", name: "sides"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawCylinderEx", - description: "Draw a cylinder with base at startPos and top at endPos", - returnType: "void", - params: [ - {type: "Vector3", name: "startPos"}, - {type: "Vector3", name: "endPos"}, - {type: "float", name: "startRadius"}, - {type: "float", name: "endRadius"}, - {type: "int", name: "sides"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawCylinderWires", - description: "Draw a cylinder/cone wires", - returnType: "void", - params: [ - {type: "Vector3", name: "position"}, - {type: "float", name: "radiusTop"}, - {type: "float", name: "radiusBottom"}, - {type: "float", name: "height"}, - {type: "int", name: "sides"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawCylinderWiresEx", - description: "Draw a cylinder wires with base at startPos and top at endPos", - returnType: "void", - params: [ - {type: "Vector3", name: "startPos"}, - {type: "Vector3", name: "endPos"}, - {type: "float", name: "startRadius"}, - {type: "float", name: "endRadius"}, - {type: "int", name: "sides"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawCapsule", - description: "Draw a capsule with the center of its sphere caps at startPos and endPos", - returnType: "void", - params: [ - {type: "Vector3", name: "startPos"}, - {type: "Vector3", name: "endPos"}, - {type: "float", name: "radius"}, - {type: "int", name: "rings"}, - {type: "int", name: "slices"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawCapsuleWires", - description: "Draw capsule wireframe with the center of its sphere caps at startPos and endPos", - returnType: "void", - params: [ - {type: "Vector3", name: "startPos"}, - {type: "Vector3", name: "endPos"}, - {type: "float", name: "radius"}, - {type: "int", name: "rings"}, - {type: "int", name: "slices"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawPlane", - description: "Draw a plane XZ", - returnType: "void", - params: [ - {type: "Vector3", name: "centerPos"}, - {type: "Vector2", name: "size"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawRay", - description: "Draw a ray line", - returnType: "void", - params: [ - {type: "Ray", name: "ray"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawGrid", - description: "Draw a grid (centered at (0, 0, 0))", - returnType: "void", - params: [ - {type: "int", name: "slices"}, - {type: "float", name: "spacing"} - ] - }, - { - name: "LoadModel", - description: "Load model from files (meshes and materials)", - returnType: "Model", - params: [ - {type: "const char *", name: "fileName"} - ] - }, - { - name: "LoadModelFromMesh", - description: "Load model from generated mesh (default material)", - returnType: "Model", - params: [ - {type: "Mesh", name: "mesh"} - ] - }, - { - name: "IsModelValid", - description: "Check if model is valid (loaded in GPU, VAO/VBOs)", - returnType: "bool", - params: [ - {type: "Model", name: "model"} - ] - }, - { - name: "UnloadModel", - description: "Unload model (including meshes) from memory (RAM and/or VRAM)", - returnType: "void", - params: [ - {type: "Model", name: "model"} - ] - }, - { - name: "GetModelBoundingBox", - description: "Compute model bounding box limits (considers all meshes)", - returnType: "BoundingBox", - params: [ - {type: "Model", name: "model"} - ] - }, - { - name: "DrawModel", - description: "Draw a model (with texture if set)", - returnType: "void", - params: [ - {type: "Model", name: "model"}, - {type: "Vector3", name: "position"}, - {type: "float", name: "scale"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "DrawModelEx", - description: "Draw a model with extended parameters", - returnType: "void", - params: [ - {type: "Model", name: "model"}, - {type: "Vector3", name: "position"}, - {type: "Vector3", name: "rotationAxis"}, - {type: "float", name: "rotationAngle"}, - {type: "Vector3", name: "scale"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "DrawModelWires", - description: "Draw a model wires (with texture if set)", - returnType: "void", - params: [ - {type: "Model", name: "model"}, - {type: "Vector3", name: "position"}, - {type: "float", name: "scale"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "DrawModelWiresEx", - description: "Draw a model wires (with texture if set) with extended parameters", - returnType: "void", - params: [ - {type: "Model", name: "model"}, - {type: "Vector3", name: "position"}, - {type: "Vector3", name: "rotationAxis"}, - {type: "float", name: "rotationAngle"}, - {type: "Vector3", name: "scale"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "DrawBoundingBox", - description: "Draw bounding box (wires)", - returnType: "void", - params: [ - {type: "BoundingBox", name: "box"}, - {type: "Color", name: "color"} - ] - }, - { - name: "DrawBillboard", - description: "Draw a billboard texture", - returnType: "void", - params: [ - {type: "Camera", name: "camera"}, - {type: "Texture2D", name: "texture"}, - {type: "Vector3", name: "position"}, - {type: "float", name: "scale"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "DrawBillboardRec", - description: "Draw a billboard texture defined by rectangle", - returnType: "void", - params: [ - {type: "Camera", name: "camera"}, - {type: "Texture2D", name: "texture"}, - {type: "Rectangle", name: "rec"}, - {type: "Vector3", name: "position"}, - {type: "Vector2", name: "size"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "DrawBillboardPro", - description: "Draw a billboard texture defined by source rectangle with scaling and rotation", - returnType: "void", - params: [ - {type: "Camera", name: "camera"}, - {type: "Texture2D", name: "texture"}, - {type: "Rectangle", name: "rec"}, - {type: "Vector3", name: "position"}, - {type: "Vector3", name: "up"}, - {type: "Vector2", name: "size"}, - {type: "Vector2", name: "origin"}, - {type: "float", name: "rotation"}, - {type: "Color", name: "tint"} - ] - }, - { - name: "UploadMesh", - description: "Upload mesh vertex data in GPU and provide VAO/VBO ids", - returnType: "void", - params: [ - {type: "Mesh *", name: "mesh"}, - {type: "bool", name: "dynamic"} - ] - }, - { - name: "UpdateMeshBuffer", - description: "Update mesh vertex data in GPU for a specific buffer index", - returnType: "void", - params: [ - {type: "Mesh", name: "mesh"}, - {type: "int", name: "index"}, - {type: "const void *", name: "data"}, - {type: "int", name: "dataSize"}, - {type: "int", name: "offset"} - ] - }, - { - name: "UnloadMesh", - description: "Unload mesh data from CPU and GPU", - returnType: "void", - params: [ - {type: "Mesh", name: "mesh"} - ] - }, - { - name: "DrawMesh", - description: "Draw a 3d mesh with material and transform", - returnType: "void", - params: [ - {type: "Mesh", name: "mesh"}, - {type: "Material", name: "material"}, - {type: "Matrix", name: "transform"} - ] - }, - { - name: "DrawMeshInstanced", - description: "Draw multiple mesh instances with material and different transforms", - returnType: "void", - params: [ - {type: "Mesh", name: "mesh"}, - {type: "Material", name: "material"}, - {type: "const Matrix *", name: "transforms"}, - {type: "int", name: "instances"} - ] - }, - { - name: "GetMeshBoundingBox", - description: "Compute mesh bounding box limits", - returnType: "BoundingBox", - params: [ - {type: "Mesh", name: "mesh"} - ] - }, - { - name: "GenMeshTangents", - description: "Compute mesh tangents", - returnType: "void", - params: [ - {type: "Mesh *", name: "mesh"} - ] - }, - { - name: "ExportMesh", - description: "Export mesh data to file, returns true on success", - returnType: "bool", - params: [ - {type: "Mesh", name: "mesh"}, - {type: "const char *", name: "fileName"} - ] - }, - { - name: "ExportMeshAsCode", - description: "Export mesh as code file (.h) defining multiple arrays of vertex attributes", - returnType: "bool", - params: [ - {type: "Mesh", name: "mesh"}, - {type: "const char *", name: "fileName"} - ] - }, - { - name: "GenMeshPoly", - description: "Generate polygonal mesh", - returnType: "Mesh", - params: [ - {type: "int", name: "sides"}, - {type: "float", name: "radius"} - ] - }, - { - name: "GenMeshPlane", - description: "Generate plane mesh (with subdivisions)", - returnType: "Mesh", - params: [ - {type: "float", name: "width"}, - {type: "float", name: "length"}, - {type: "int", name: "resX"}, - {type: "int", name: "resZ"} - ] - }, - { - name: "GenMeshCube", - description: "Generate cuboid mesh", - returnType: "Mesh", - params: [ - {type: "float", name: "width"}, - {type: "float", name: "height"}, - {type: "float", name: "length"} - ] - }, - { - name: "GenMeshSphere", - description: "Generate sphere mesh (standard sphere)", - returnType: "Mesh", - params: [ - {type: "float", name: "radius"}, - {type: "int", name: "rings"}, - {type: "int", name: "slices"} - ] - }, - { - name: "GenMeshHemiSphere", - description: "Generate half-sphere mesh (no bottom cap)", - returnType: "Mesh", - params: [ - {type: "float", name: "radius"}, - {type: "int", name: "rings"}, - {type: "int", name: "slices"} - ] - }, - { - name: "GenMeshCylinder", - description: "Generate cylinder mesh", - returnType: "Mesh", - params: [ - {type: "float", name: "radius"}, - {type: "float", name: "height"}, - {type: "int", name: "slices"} - ] - }, - { - name: "GenMeshCone", - description: "Generate cone/pyramid mesh", - returnType: "Mesh", - params: [ - {type: "float", name: "radius"}, - {type: "float", name: "height"}, - {type: "int", name: "slices"} - ] - }, - { - name: "GenMeshTorus", - description: "Generate torus mesh", - returnType: "Mesh", - params: [ - {type: "float", name: "radius"}, - {type: "float", name: "size"}, - {type: "int", name: "radSeg"}, - {type: "int", name: "sides"} - ] - }, - { - name: "GenMeshKnot", - description: "Generate trefoil knot mesh", - returnType: "Mesh", - params: [ - {type: "float", name: "radius"}, - {type: "float", name: "size"}, - {type: "int", name: "radSeg"}, - {type: "int", name: "sides"} - ] - }, - { - name: "GenMeshHeightmap", - description: "Generate heightmap mesh from image data", - returnType: "Mesh", - params: [ - {type: "Image", name: "heightmap"}, - {type: "Vector3", name: "size"} - ] - }, - { - name: "GenMeshCubicmap", - description: "Generate cubes-based map mesh from image data", - returnType: "Mesh", - params: [ - {type: "Image", name: "cubicmap"}, - {type: "Vector3", name: "cubeSize"} - ] - }, - { - name: "LoadMaterials", - description: "Load materials from model file", - returnType: "Material *", - params: [ - {type: "const char *", name: "fileName"}, - {type: "int *", name: "materialCount"} - ] - }, - { - name: "LoadMaterialDefault", - description: "Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps)", - returnType: "Material" - }, - { - name: "IsMaterialValid", - description: "Check if material is valid (shader assigned, map textures loaded in GPU)", - returnType: "bool", - params: [ - {type: "Material", name: "material"} - ] - }, - { - name: "UnloadMaterial", - description: "Unload material from GPU memory (VRAM)", - returnType: "void", - params: [ - {type: "Material", name: "material"} - ] - }, - { - name: "SetMaterialTexture", - description: "Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...)", - returnType: "void", - params: [ - {type: "Material *", name: "material"}, - {type: "int", name: "mapType"}, - {type: "Texture2D", name: "texture"} - ] - }, - { - name: "SetModelMeshMaterial", - description: "Set material for a mesh", - returnType: "void", - params: [ - {type: "Model *", name: "model"}, - {type: "int", name: "meshId"}, - {type: "int", name: "materialId"} - ] - }, - { - name: "LoadModelAnimations", - description: "Load model animations from file", - returnType: "ModelAnimation *", - params: [ - {type: "const char *", name: "fileName"}, - {type: "int *", name: "animCount"} - ] - }, - { - name: "UpdateModelAnimation", - description: "Update model animation pose (vertex buffers and bone matrices)", - returnType: "void", - params: [ - {type: "Model", name: "model"}, - {type: "ModelAnimation", name: "anim"}, - {type: "float", name: "frame"} - ] - }, - { - name: "UpdateModelAnimationEx", - description: "Update model animation pose, blending two animations", - returnType: "void", - params: [ - {type: "Model", name: "model"}, - {type: "ModelAnimation", name: "animA"}, - {type: "float", name: "frameA"}, - {type: "ModelAnimation", name: "animB"}, - {type: "float", name: "frameB"}, - {type: "float", name: "blend"} - ] - }, - { - name: "UnloadModelAnimations", - description: "Unload animation array data", - returnType: "void", - params: [ - {type: "ModelAnimation *", name: "animations"}, - {type: "int", name: "animCount"} - ] - }, - { - name: "IsModelAnimationValid", - description: "Check model animation skeleton match", - returnType: "bool", - params: [ - {type: "Model", name: "model"}, - {type: "ModelAnimation", name: "anim"} - ] - }, - { - name: "CheckCollisionSpheres", - description: "Check collision between two spheres", - returnType: "bool", - params: [ - {type: "Vector3", name: "center1"}, - {type: "float", name: "radius1"}, - {type: "Vector3", name: "center2"}, - {type: "float", name: "radius2"} - ] - }, - { - name: "CheckCollisionBoxes", - description: "Check collision between two bounding boxes", - returnType: "bool", - params: [ - {type: "BoundingBox", name: "box1"}, - {type: "BoundingBox", name: "box2"} - ] - }, - { - name: "CheckCollisionBoxSphere", - description: "Check collision between box and sphere", - returnType: "bool", - params: [ - {type: "BoundingBox", name: "box"}, - {type: "Vector3", name: "center"}, - {type: "float", name: "radius"} - ] - }, - { - name: "GetRayCollisionSphere", - description: "Get collision info between ray and sphere", - returnType: "RayCollision", - params: [ - {type: "Ray", name: "ray"}, - {type: "Vector3", name: "center"}, - {type: "float", name: "radius"} - ] - }, - { - name: "GetRayCollisionBox", - description: "Get collision info between ray and box", - returnType: "RayCollision", - params: [ - {type: "Ray", name: "ray"}, - {type: "BoundingBox", name: "box"} - ] - }, - { - name: "GetRayCollisionMesh", - description: "Get collision info between ray and mesh", - returnType: "RayCollision", - params: [ - {type: "Ray", name: "ray"}, - {type: "Mesh", name: "mesh"}, - {type: "Matrix", name: "transform"} - ] - }, - { - name: "GetRayCollisionTriangle", - description: "Get collision info between ray and triangle", - returnType: "RayCollision", - params: [ - {type: "Ray", name: "ray"}, - {type: "Vector3", name: "p1"}, - {type: "Vector3", name: "p2"}, - {type: "Vector3", name: "p3"} - ] - }, - { - name: "GetRayCollisionQuad", - description: "Get collision info between ray and quad", - returnType: "RayCollision", - params: [ - {type: "Ray", name: "ray"}, - {type: "Vector3", name: "p1"}, - {type: "Vector3", name: "p2"}, - {type: "Vector3", name: "p3"}, - {type: "Vector3", name: "p4"} - ] - }, - { - name: "InitAudioDevice", - description: "Initialize audio device and context", - returnType: "void" - }, - { - name: "CloseAudioDevice", - description: "Close the audio device and context", - returnType: "void" - }, - { - name: "IsAudioDeviceReady", - description: "Check if audio device has been initialized successfully", - returnType: "bool" - }, - { - name: "SetMasterVolume", - description: "Set master volume (listener)", - returnType: "void", - params: [ - {type: "float", name: "volume"} - ] - }, - { - name: "GetMasterVolume", - description: "Get master volume (listener)", - returnType: "float" - }, - { - name: "LoadWave", - description: "Load wave data from file", - returnType: "Wave", - params: [ - {type: "const char *", name: "fileName"} - ] - }, - { - name: "LoadWaveFromMemory", - description: "Load wave from memory buffer, fileType refers to extension: i.e. '.wav'", - returnType: "Wave", - params: [ - {type: "const char *", name: "fileType"}, - {type: "const unsigned char *", name: "fileData"}, - {type: "int", name: "dataSize"} - ] - }, - { - name: "IsWaveValid", - description: "Check if wave data is valid (data loaded and parameters)", - returnType: "bool", - params: [ - {type: "Wave", name: "wave"} - ] - }, - { - name: "LoadSound", - description: "Load sound from file", - returnType: "Sound", - params: [ - {type: "const char *", name: "fileName"} - ] - }, - { - name: "LoadSoundFromWave", - description: "Load sound from wave data", - returnType: "Sound", - params: [ - {type: "Wave", name: "wave"} - ] - }, - { - name: "LoadSoundAlias", - description: "Load sound alias, new sound that shares the same sample data as the source sound, does not own the sound data", - returnType: "Sound", - params: [ - {type: "Sound", name: "source"} - ] - }, - { - name: "IsSoundValid", - description: "Check if sound is valid (data loaded and buffers initialized)", - returnType: "bool", - params: [ - {type: "Sound", name: "sound"} - ] - }, - { - name: "UpdateSound", - description: "Update sound buffer with new data (default data format: 32 bit float, stereo)", - returnType: "void", - params: [ - {type: "Sound", name: "sound"}, - {type: "const void *", name: "data"}, - {type: "int", name: "frameCount"} - ] - }, - { - name: "UnloadWave", - description: "Unload wave data", - returnType: "void", - params: [ - {type: "Wave", name: "wave"} - ] - }, - { - name: "UnloadSound", - description: "Unload sound", - returnType: "void", - params: [ - {type: "Sound", name: "sound"} - ] - }, - { - name: "UnloadSoundAlias", - description: "Unload sound alias (does not deallocate sample data)", - returnType: "void", - params: [ - {type: "Sound", name: "alias"} - ] - }, - { - name: "ExportWave", - description: "Export wave data to file, returns true on success", - returnType: "bool", - params: [ - {type: "Wave", name: "wave"}, - {type: "const char *", name: "fileName"} - ] - }, - { - name: "ExportWaveAsCode", - description: "Export wave sample data to code (.h), returns true on success", - returnType: "bool", - params: [ - {type: "Wave", name: "wave"}, - {type: "const char *", name: "fileName"} - ] - }, - { - name: "PlaySound", - description: "Play a sound", - returnType: "void", - params: [ - {type: "Sound", name: "sound"} - ] - }, - { - name: "StopSound", - description: "Stop playing a sound", - returnType: "void", - params: [ - {type: "Sound", name: "sound"} - ] - }, - { - name: "PauseSound", - description: "Pause a sound", - returnType: "void", - params: [ - {type: "Sound", name: "sound"} - ] - }, - { - name: "ResumeSound", - description: "Resume a paused sound", - returnType: "void", - params: [ - {type: "Sound", name: "sound"} - ] - }, - { - name: "IsSoundPlaying", - description: "Check if sound is currently playing", - returnType: "bool", - params: [ - {type: "Sound", name: "sound"} - ] - }, - { - name: "SetSoundVolume", - description: "Set volume for a sound (1.0 is max level)", - returnType: "void", - params: [ - {type: "Sound", name: "sound"}, - {type: "float", name: "volume"} - ] - }, - { - name: "SetSoundPitch", - description: "Set pitch for a sound (1.0 is base level)", - returnType: "void", - params: [ - {type: "Sound", name: "sound"}, - {type: "float", name: "pitch"} - ] - }, - { - name: "SetSoundPan", - description: "Set pan for a sound (-1.0 left, 0.0 center, 1.0 right)", - returnType: "void", - params: [ - {type: "Sound", name: "sound"}, - {type: "float", name: "pan"} - ] - }, - { - name: "WaveCopy", - description: "Copy a wave to a new wave", - returnType: "Wave", - params: [ - {type: "Wave", name: "wave"} - ] - }, - { - name: "WaveCrop", - description: "Crop a wave to defined frames range", - returnType: "void", - params: [ - {type: "Wave *", name: "wave"}, - {type: "int", name: "initFrame"}, - {type: "int", name: "finalFrame"} - ] - }, - { - name: "WaveFormat", - description: "Convert wave data to desired format", - returnType: "void", - params: [ - {type: "Wave *", name: "wave"}, - {type: "int", name: "sampleRate"}, - {type: "int", name: "sampleSize"}, - {type: "int", name: "channels"} - ] - }, - { - name: "LoadWaveSamples", - description: "Load samples data from wave as a 32bit float data array", - returnType: "float *", - params: [ - {type: "Wave", name: "wave"} - ] - }, - { - name: "UnloadWaveSamples", - description: "Unload samples data loaded with LoadWaveSamples()", - returnType: "void", - params: [ - {type: "float *", name: "samples"} - ] - }, - { - name: "LoadMusicStream", - description: "Load music stream from file", - returnType: "Music", - params: [ - {type: "const char *", name: "fileName"} - ] - }, - { - name: "LoadMusicStreamFromMemory", - description: "Load music stream from data", - returnType: "Music", - params: [ - {type: "const char *", name: "fileType"}, - {type: "const unsigned char *", name: "data"}, - {type: "int", name: "dataSize"} - ] - }, - { - name: "IsMusicValid", - description: "Check if music stream is valid (context and buffers initialized)", - returnType: "bool", - params: [ - {type: "Music", name: "music"} - ] - }, - { - name: "UnloadMusicStream", - description: "Unload music stream", - returnType: "void", - params: [ - {type: "Music", name: "music"} - ] - }, - { - name: "PlayMusicStream", - description: "Start music playing", - returnType: "void", - params: [ - {type: "Music", name: "music"} - ] - }, - { - name: "IsMusicStreamPlaying", - description: "Check if music is playing", - returnType: "bool", - params: [ - {type: "Music", name: "music"} - ] - }, - { - name: "UpdateMusicStream", - description: "Update buffers for music streaming", - returnType: "void", - params: [ - {type: "Music", name: "music"} - ] - }, - { - name: "StopMusicStream", - description: "Stop music playing", - returnType: "void", - params: [ - {type: "Music", name: "music"} - ] - }, - { - name: "PauseMusicStream", - description: "Pause music playing", - returnType: "void", - params: [ - {type: "Music", name: "music"} - ] - }, - { - name: "ResumeMusicStream", - description: "Resume playing paused music", - returnType: "void", - params: [ - {type: "Music", name: "music"} - ] - }, - { - name: "SeekMusicStream", - description: "Seek music to a position (in seconds)", - returnType: "void", - params: [ - {type: "Music", name: "music"}, - {type: "float", name: "position"} - ] - }, - { - name: "SetMusicVolume", - description: "Set volume for music (1.0 is max level)", - returnType: "void", - params: [ - {type: "Music", name: "music"}, - {type: "float", name: "volume"} - ] - }, - { - name: "SetMusicPitch", - description: "Set pitch for music (1.0 is base level)", - returnType: "void", - params: [ - {type: "Music", name: "music"}, - {type: "float", name: "pitch"} - ] - }, - { - name: "SetMusicPan", - description: "Set pan for music (-1.0 left, 0.0 center, 1.0 right)", - returnType: "void", - params: [ - {type: "Music", name: "music"}, - {type: "float", name: "pan"} - ] - }, - { - name: "GetMusicTimeLength", - description: "Get music time length (in seconds)", - returnType: "float", - params: [ - {type: "Music", name: "music"} - ] - }, - { - name: "GetMusicTimePlayed", - description: "Get current music time played (in seconds)", - returnType: "float", - params: [ - {type: "Music", name: "music"} - ] - }, - { - name: "LoadAudioStream", - description: "Load audio stream (to stream raw audio pcm data)", - returnType: "AudioStream", - params: [ - {type: "unsigned int", name: "sampleRate"}, - {type: "unsigned int", name: "sampleSize"}, - {type: "unsigned int", name: "channels"} - ] - }, - { - name: "IsAudioStreamValid", - description: "Check if an audio stream is valid (buffers initialized)", - returnType: "bool", - params: [ - {type: "AudioStream", name: "stream"} - ] - }, - { - name: "UnloadAudioStream", - description: "Unload audio stream and free memory", - returnType: "void", - params: [ - {type: "AudioStream", name: "stream"} - ] - }, - { - name: "UpdateAudioStream", - description: "Update audio stream buffers with data", - returnType: "void", - params: [ - {type: "AudioStream", name: "stream"}, - {type: "const void *", name: "data"}, - {type: "int", name: "frameCount"} - ] - }, - { - name: "IsAudioStreamProcessed", - description: "Check if any audio stream buffers requires refill", - returnType: "bool", - params: [ - {type: "AudioStream", name: "stream"} - ] - }, - { - name: "PlayAudioStream", - description: "Play audio stream", - returnType: "void", - params: [ - {type: "AudioStream", name: "stream"} - ] - }, - { - name: "PauseAudioStream", - description: "Pause audio stream", - returnType: "void", - params: [ - {type: "AudioStream", name: "stream"} - ] - }, - { - name: "ResumeAudioStream", - description: "Resume audio stream", - returnType: "void", - params: [ - {type: "AudioStream", name: "stream"} - ] - }, - { - name: "IsAudioStreamPlaying", - description: "Check if audio stream is playing", - returnType: "bool", - params: [ - {type: "AudioStream", name: "stream"} - ] - }, - { - name: "StopAudioStream", - description: "Stop audio stream", - returnType: "void", - params: [ - {type: "AudioStream", name: "stream"} - ] - }, - { - name: "SetAudioStreamVolume", - description: "Set volume for audio stream (1.0 is max level)", - returnType: "void", - params: [ - {type: "AudioStream", name: "stream"}, - {type: "float", name: "volume"} - ] - }, - { - name: "SetAudioStreamPitch", - description: "Set pitch for audio stream (1.0 is base level)", - returnType: "void", - params: [ - {type: "AudioStream", name: "stream"}, - {type: "float", name: "pitch"} - ] - }, - { - name: "SetAudioStreamPan", - description: "Set pan for audio stream (-1.0 left, 0.0 center, 1.0 right)", - returnType: "void", - params: [ - {type: "AudioStream", name: "stream"}, - {type: "float", name: "pan"} - ] - }, - { - name: "SetAudioStreamBufferSizeDefault", - description: "Default size for new audio streams", - returnType: "void", - params: [ - {type: "int", name: "size"} - ] - }, - { - name: "SetAudioStreamCallback", - description: "Audio thread callback to request new data", - returnType: "void", - params: [ - {type: "AudioStream", name: "stream"}, - {type: "AudioCallback", name: "callback"} - ] - }, - { - name: "AttachAudioStreamProcessor", - description: "Attach audio stream processor to stream, receives frames x 2 samples as 'float' (stereo)", - returnType: "void", - params: [ - {type: "AudioStream", name: "stream"}, - {type: "AudioCallback", name: "processor"} - ] - }, - { - name: "DetachAudioStreamProcessor", - description: "Detach audio stream processor from stream", - returnType: "void", - params: [ - {type: "AudioStream", name: "stream"}, - {type: "AudioCallback", name: "processor"} - ] - }, - { - name: "AttachAudioMixedProcessor", - description: "Attach audio stream processor to the entire audio pipeline, receives frames x 2 samples as 'float' (stereo)", - returnType: "void", - params: [ - {type: "AudioCallback", name: "processor"} - ] - }, - { - name: "DetachAudioMixedProcessor", - description: "Detach audio stream processor from the entire audio pipeline", - returnType: "void", - params: [ - {type: "AudioCallback", name: "processor"} - ] - } - ] -}; diff --git a/tools/rlparser/rlparser.c b/tools/rlparser/rlparser.c index 9fd94c564..dc2afe114 100644 --- a/tools/rlparser/rlparser.c +++ b/tools/rlparser/rlparser.c @@ -146,7 +146,7 @@ typedef struct FunctionInfo { } FunctionInfo; // Output format for parsed data -typedef enum { DEFAULT = 0, JSON, XML, LUA, JS, CODE } OutputFormat; +typedef enum { DEFAULT = 0, JSON, XML, LUA, CODE } OutputFormat; //---------------------------------------------------------------------------------- // Global Variables Definition @@ -1062,7 +1062,6 @@ int main(int argc, char *argv[]) else if (outputFormat == JSON) printf("\nOutput format: JSON\n\n"); else if (outputFormat == XML) printf("\nOutput format: XML\n\n"); else if (outputFormat == LUA) printf("\nOutput format: LUA\n\n"); - else if (outputFormat == JS) printf("\nOutput format: JS\n\n"); else if (outputFormat == CODE) printf("\nOutput format: CODE\n\n"); ExportParsedData(outFileName, outputFormat); @@ -1099,10 +1098,10 @@ static void ShowCommandLineInfo(void) printf(" -i, --input : Define input header file to parse.\n"); printf(" NOTE: If not specified, defaults to: raylib.h\n\n"); printf(" -o, --output : Define output file and format.\n"); - printf(" Supported extensions: .txt, .json, .xml, .lua, .js, .h\n"); + printf(" Supported extensions: .txt, .json, .xml, .lua, .h\n"); printf(" NOTE: If not specified, defaults to: raylib_api.txt\n\n"); printf(" -f, --format : Define output format for parser data.\n"); - printf(" Supported types: DEFAULT, JSON, XML, LUA, JS, CODE\n\n"); + printf(" Supported types: DEFAULT, JSON, XML, LUA, CODE\n\n"); printf(" -d, --define : Define functions specifiers (i.e. RLAPI for raylib.h, RMAPI for raymath.h, etc.)\n"); printf(" NOTE: If no specifier defined, defaults to: RLAPI\n\n"); printf(" -t, --truncate : Define string to truncate input after (i.e. \"RLGL IMPLEMENTATION\" for rlgl.h)\n"); @@ -1155,7 +1154,6 @@ static void ProcessCommandLine(int argc, char *argv[]) else if (IsTextEqual(argv[i + 1], "JSON\0", 5)) outputFormat = JSON; else if (IsTextEqual(argv[i + 1], "XML\0", 4)) outputFormat = XML; else if (IsTextEqual(argv[i + 1], "LUA\0", 4)) outputFormat = LUA; - else if (IsTextEqual(argv[i + 1], "JS\0", 3)) outputFormat = JS; else if (IsTextEqual(argv[i + 1], "CODE\0", 5)) outputFormat = CODE; } else printf("WARNING: No format parameters provided\n"); @@ -1865,8 +1863,8 @@ static void ExportParsedData(const char *fileName, int format) for (int i = 0; i < defineCount; i++) { fprintf(outFile, " {\n"); - fprintf(outFile, " name: \"%s\",\n", defines[i].name); - fprintf(outFile, " type: \"%s\",\n", StrDefineType(defines[i].type)); + fprintf(outFile, " name = \"%s\",\n", defines[i].name); + fprintf(outFile, " type = \"%s\",\n", StrDefineType(defines[i].type)); if ((defines[i].type == INT) || (defines[i].type == LONG) || (defines[i].type == FLOAT) || @@ -2009,159 +2007,6 @@ static void ExportParsedData(const char *fileName, int format) fprintf(outFile, " }\n"); fprintf(outFile, "}\n"); } break; - case JS: - { - fprintf(outFile, "export default {\n"); - - // Print defines info - fprintf(outFile, " defines: [\n"); - for (int i = 0; i < defineCount; i++) - { - fprintf(outFile, " {\n"); - fprintf(outFile, " name: \"%s\",\n", defines[i].name); - fprintf(outFile, " type: \"%s\",\n", StrDefineType(defines[i].type)); - if ((defines[i].type == INT) || - (defines[i].type == LONG) || - (defines[i].type == FLOAT) || - (defines[i].type == DOUBLE) || - (defines[i].type == STRING)) - { - fprintf(outFile, " value: %s,\n", defines[i].value); - } - else - { - fprintf(outFile, " value: \"%s\",\n", defines[i].value); - } - fprintf(outFile, " description: \"%s\"\n", defines[i].desc); - fprintf(outFile, " }"); - - if (i < defineCount - 1) fprintf(outFile, ",\n"); - else fprintf(outFile, "\n"); - } - fprintf(outFile, " ],\n"); - - // Print structs info - fprintf(outFile, " structs: [\n"); - for (int i = 0; i < structCount; i++) - { - fprintf(outFile, " {\n"); - fprintf(outFile, " name: \"%s\",\n", structs[i].name); - fprintf(outFile, " description: \"%s\",\n", EscapeBackslashes(structs[i].desc)); - fprintf(outFile, " fields: [\n"); - for (int f = 0; f < structs[i].fieldCount; f++) - { - fprintf(outFile, " {\n"); - fprintf(outFile, " type: \"%s\",\n", structs[i].fieldType[f]); - fprintf(outFile, " name: \"%s\",\n", structs[i].fieldName[f]); - fprintf(outFile, " description: \"%s\"\n", EscapeBackslashes(structs[i].fieldDesc[f])); - fprintf(outFile, " }"); - if (f < structs[i].fieldCount - 1) fprintf(outFile, ",\n"); - else fprintf(outFile, "\n"); - } - fprintf(outFile, " ]\n"); - fprintf(outFile, " }"); - if (i < structCount - 1) fprintf(outFile, ",\n"); - else fprintf(outFile, "\n"); - } - fprintf(outFile, " ],\n"); - - // Print aliases info - fprintf(outFile, " aliases: [\n"); - for (int i = 0; i < aliasCount; i++) - { - fprintf(outFile, " {\n"); - fprintf(outFile, " type: \"%s\",\n", aliases[i].type); - fprintf(outFile, " name: \"%s\",\n", aliases[i].name); - fprintf(outFile, " description: \"%s\"\n", aliases[i].desc); - fprintf(outFile, " }"); - - if (i < aliasCount - 1) fprintf(outFile, ",\n"); - else fprintf(outFile, "\n"); - } - fprintf(outFile, " ],\n"); - - // Print enums info - fprintf(outFile, " enums: [\n"); - for (int i = 0; i < enumCount; i++) - { - fprintf(outFile, " {\n"); - fprintf(outFile, " name: \"%s\",\n", enums[i].name); - fprintf(outFile, " description: \"%s\",\n", EscapeBackslashes(enums[i].desc)); - fprintf(outFile, " values: [\n"); - for (int e = 0; e < enums[i].valueCount; e++) - { - fprintf(outFile, " {\n"); - fprintf(outFile, " name: \"%s\",\n", enums[i].valueName[e]); - fprintf(outFile, " value: %i,\n", enums[i].valueInteger[e]); - fprintf(outFile, " description: \"%s\"\n", EscapeBackslashes(enums[i].valueDesc[e])); - fprintf(outFile, " }"); - if (e < enums[i].valueCount - 1) fprintf(outFile, ",\n"); - else fprintf(outFile, "\n"); - } - fprintf(outFile, " ]\n"); - fprintf(outFile, " }"); - if (i < enumCount - 1) fprintf(outFile, ",\n"); - else fprintf(outFile, "\n"); - } - fprintf(outFile, " ],\n"); - - // Print callbacks info - fprintf(outFile, " callbacks: [\n"); - for (int i = 0; i < callbackCount; i++) - { - fprintf(outFile, " {\n"); - fprintf(outFile, " name: \"%s\",\n", callbacks[i].name); - fprintf(outFile, " description: \"%s\",\n", EscapeBackslashes(callbacks[i].desc)); - fprintf(outFile, " returnType: \"%s\"", callbacks[i].retType); - - if (callbacks[i].paramCount == 0) fprintf(outFile, "\n"); - else - { - fprintf(outFile, ",\n params: [\n"); - for (int p = 0; p < callbacks[i].paramCount; p++) - { - fprintf(outFile, " {type: \"%s\", name: \"%s\"}", callbacks[i].paramType[p], callbacks[i].paramName[p]); - if (p < callbacks[i].paramCount - 1) fprintf(outFile, ",\n"); - else fprintf(outFile, "\n"); - } - fprintf(outFile, " ]\n"); - } - fprintf(outFile, " }"); - - if (i < callbackCount - 1) fprintf(outFile, ",\n"); - else fprintf(outFile, "\n"); - } - fprintf(outFile, " ],\n"); - - // Print functions info - fprintf(outFile, " functions: [\n"); - for (int i = 0; i < funcCount; i++) - { - fprintf(outFile, " {\n"); - fprintf(outFile, " name: \"%s\",\n", funcs[i].name); - fprintf(outFile, " description: \"%s\",\n", EscapeBackslashes(funcs[i].desc)); - fprintf(outFile, " returnType: \"%s\"", funcs[i].retType); - - if (funcs[i].paramCount == 0) fprintf(outFile, "\n"); - else - { - fprintf(outFile, ",\n params: [\n"); - for (int p = 0; p < funcs[i].paramCount; p++) - { - fprintf(outFile, " {type: \"%s\", name: \"%s\"}", funcs[i].paramType[p], funcs[i].paramName[p]); - if (p < funcs[i].paramCount - 1) fprintf(outFile, ",\n"); - else fprintf(outFile, "\n"); - } - fprintf(outFile, " ]\n"); - } - fprintf(outFile, " }"); - - if (i < funcCount - 1) fprintf(outFile, ",\n"); - else fprintf(outFile, "\n"); - } - fprintf(outFile, " ]\n"); - fprintf(outFile, "};\n"); - } break; case CODE: default: break; } From ba3b8f837051d3a58b27fc82fcc6177ed89016f1 Mon Sep 17 00:00:00 2001 From: eu <82298389+EugenioBarbieriViale@users.noreply.github.com> Date: Wed, 24 Jun 2026 08:36:30 +0000 Subject: [PATCH 11/94] Add comments for GenMeshTorus (#5934) --- src/rmodels.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/rmodels.c b/src/rmodels.c index 3198e47a4..8e87ccfa2 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -3142,6 +3142,8 @@ Mesh GenMeshCone(float radius, float height, int slices) } // Generate torus mesh +// The distance between the center of the hole and the center of the tube is half of size +// The radius of the tube is (radius * size / 2) Mesh GenMeshTorus(float radius, float size, int radSeg, int sides) { Mesh mesh = { 0 }; From d1a14bee5d9f24a84ad82431e36a5ff96768d75c Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 24 Jun 2026 10:38:20 +0200 Subject: [PATCH 12/94] Update rmodels.c --- src/rmodels.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index 8e87ccfa2..28fb3c9ec 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -3142,8 +3142,8 @@ Mesh GenMeshCone(float radius, float height, int slices) } // Generate torus mesh -// The distance between the center of the hole and the center of the tube is half of size -// The radius of the tube is (radius * size / 2) +// NOTE: The distance between the center of the hole and the center of the +// tube is half size of the radius of the tube (radius*size/2) Mesh GenMeshTorus(float radius, float size, int radSeg, int sides) { Mesh mesh = { 0 }; From 83cb4cc21089347b7df9f476586ed328be15e1f0 Mon Sep 17 00:00:00 2001 From: Brandon Arrendondo Date: Wed, 24 Jun 2026 10:38:08 -0400 Subject: [PATCH 13/94] [rlgl] Fix matrix stack overflow in rlPushMatrix() (#5935) The RL_MAX_MATRIX_STACK_SIZE check logged an error but did not return, so RLGL.State.stack[stackCounter] = *currentMatrix still executed when the stack was full -- writing one element past stack[RL_MAX_MATRIX_STACK_SIZE] and corrupting the adjacent RLGL.State members (stackCounter, etc.). rlPopMatrix() already guards the symmetric underflow case; add the missing early return. Co-authored-by: Brandon Arrendondo --- src/rlgl.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/rlgl.h b/src/rlgl.h index ed5e50fb1..8c529a4e0 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -1237,7 +1237,11 @@ void rlMatrixMode(int mode) // Push the current matrix into RLGL.State.stack void rlPushMatrix(void) { - if (RLGL.State.stackCounter >= RL_MAX_MATRIX_STACK_SIZE) TRACELOG(RL_LOG_ERROR, "RLGL: Matrix stack overflow (RL_MAX_MATRIX_STACK_SIZE)"); + if (RLGL.State.stackCounter >= RL_MAX_MATRIX_STACK_SIZE) + { + TRACELOG(RL_LOG_ERROR, "RLGL: Matrix stack overflow (RL_MAX_MATRIX_STACK_SIZE)"); + return; + } if (RLGL.State.currentMatrixMode == RL_MODELVIEW) { From 92155400155ae5917c03ba2311e0c8f8df2dc92c Mon Sep 17 00:00:00 2001 From: Brandon Arrendondo Date: Wed, 24 Jun 2026 10:41:19 -0400 Subject: [PATCH 14/94] [rtext] Fix buffer overflow in TextReplaceBetween() (#5936) The MAX_TEXT_BUFFER_LENGTH guard present in TextReplace()/TextInsert() was missing here, so the three strncpy() calls could write past the 1024-byte static buffer for long inputs. Add the same length check before copying. Co-authored-by: Brandon Arrendondo --- src/rtext.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/rtext.c b/src/rtext.c index ae28c2f98..dda08b11e 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -1919,9 +1919,13 @@ char *TextReplaceBetween(const char *text, const char *begin, const char *end, c int replaceLen = (replacement == NULL)? 0 : TextLength(replacement); //int toreplaceLen = endIndex - beginIndex - beginLen; - strncpy(buffer, text, beginIndex + beginLen); // Copy first text part - if (replacement != NULL) strncpy(buffer + beginIndex + beginLen, replacement, replaceLen); // Copy replacement (if provided) - strncpy(buffer + beginIndex + beginLen + replaceLen, text + endIndex, textLen - endIndex); // Copy end text part + if ((beginIndex + beginLen + replaceLen + (textLen - endIndex)) < (MAX_TEXT_BUFFER_LENGTH - 1)) + { + strncpy(buffer, text, beginIndex + beginLen); // Copy first text part + if (replacement != NULL) strncpy(buffer + beginIndex + beginLen, replacement, replaceLen); // Copy replacement (if provided) + strncpy(buffer + beginIndex + beginLen + replaceLen, text + endIndex, textLen - endIndex); // Copy end text part + } + else TRACELOG(LOG_WARNING, "TEXT: Text with replaced string is longer than internal buffer (MAX_TEXT_BUFFER_LENGTH)"); } } } From 3edfe194381b36ae6bafde59cfb4597afafd731c Mon Sep 17 00:00:00 2001 From: Brandon Arrendondo Date: Wed, 24 Jun 2026 11:40:28 -0400 Subject: [PATCH 15/94] [rcore] Bounds-check gamepad index in GetGamepadAxisCount() and GetGamepadName() (#5937) * [rcore] Bounds-check gamepad index in GetGamepadAxisCount() and GetGamepadName() Both public getters indexed CORE.Input.Gamepad.axisCount[gamepad] / .name[gamepad] with an unvalidated gamepad argument -- an out-of-bounds read for gamepad < 0 or gamepad >= MAX_GAMEPADS. Every sibling gamepad accessor (IsGamepadAvailable, IsGamepadButton*, GetGamepadAxisMovement) already guards the index; add the same check, returning a safe default (0 / NULL). * Refactor GetGamepadName/GetGamepadAxisCount to single-return pattern --------- Co-authored-by: Brandon Arrendondo --- src/rcore.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 7455e3597..12de4141e 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -3934,7 +3934,11 @@ bool IsGamepadAvailable(int gamepad) // Get gamepad internal name id const char *GetGamepadName(int gamepad) { - return CORE.Input.Gamepad.name[gamepad]; + const char *name = NULL; + + if ((gamepad >= 0) && (gamepad < MAX_GAMEPADS)) name = CORE.Input.Gamepad.name[gamepad]; + + return name; } // Check if gamepad button has been pressed once @@ -3999,7 +4003,11 @@ int GetGamepadButtonPressed(void) // Get gamepad axis count int GetGamepadAxisCount(int gamepad) { - return CORE.Input.Gamepad.axisCount[gamepad]; + int result = 0; + + if ((gamepad >= 0) && (gamepad < MAX_GAMEPADS)) result = CORE.Input.Gamepad.axisCount[gamepad]; + + return result; } // Get axis movement vector for a gamepad From 67359073ca2672744dba8b257bad372e6c8a87af Mon Sep 17 00:00:00 2001 From: greymoth Date: Sun, 28 Jun 2026 04:06:49 +0900 Subject: [PATCH 16/94] [rcore] Add gamepad >= 0 lower-bound guard to six sibling functions (#5938) Commit 3edfe194 added a `gamepad >= 0` lower-bound check to GetGamepadAxisCount() and GetGamepadName(), but six sibling functions were left with only the upper-bound check (`gamepad < MAX_GAMEPADS`). A negative signed int passes that check and triggers out-of-bounds access on CORE.Input.Gamepad.ready[gamepad] and related arrays (UB in C). Apply the same `(gamepad >= 0) &&` guard added in 3edfe194 to: - IsGamepadAvailable - IsGamepadButtonPressed - IsGamepadButtonDown - IsGamepadButtonReleased - IsGamepadButtonUp - GetGamepadAxisMovement --- src/rcore.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 12de4141e..070b8c0c4 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -3926,7 +3926,7 @@ bool IsGamepadAvailable(int gamepad) { bool result = false; - if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad]) result = true; + if ((gamepad >= 0) && (gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad]) result = true; return result; } @@ -3946,7 +3946,7 @@ bool IsGamepadButtonPressed(int gamepad, int button) { bool pressed = false; - if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS)) + if ((gamepad >= 0) && (gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS)) { if ((CORE.Input.Gamepad.previousButtonState[gamepad][button] == 0) && (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 1)) pressed = true; } @@ -3959,7 +3959,7 @@ bool IsGamepadButtonDown(int gamepad, int button) { bool down = false; - if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS)) + if ((gamepad >= 0) && (gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS)) { if (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 1) down = true; } @@ -3972,7 +3972,7 @@ bool IsGamepadButtonReleased(int gamepad, int button) { bool released = false; - if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS)) + if ((gamepad >= 0) && (gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS)) { if ((CORE.Input.Gamepad.previousButtonState[gamepad][button] == 1) && (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 0)) released = true; } @@ -3985,7 +3985,7 @@ bool IsGamepadButtonUp(int gamepad, int button) { bool up = false; - if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS)) + if ((gamepad >= 0) && (gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (button < MAX_GAMEPAD_BUTTONS)) { if (CORE.Input.Gamepad.currentButtonState[gamepad][button] == 0) up = true; } @@ -4015,7 +4015,7 @@ float GetGamepadAxisMovement(int gamepad, int axis) { float value = ((axis == GAMEPAD_AXIS_LEFT_TRIGGER) || (axis == GAMEPAD_AXIS_RIGHT_TRIGGER))? -1.0f : 0.0f; - if ((gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (axis < MAX_GAMEPAD_AXES)) + if ((gamepad >= 0) && (gamepad < MAX_GAMEPADS) && CORE.Input.Gamepad.ready[gamepad] && (axis < MAX_GAMEPAD_AXES)) { float movement = (value < 0.0f)? CORE.Input.Gamepad.axisState[gamepad][axis] : fabsf(CORE.Input.Gamepad.axisState[gamepad][axis]); From 7ac798cef9a2ff5c4df0efda587589bf8aa11bcc Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 1 Jul 2026 10:04:24 +0200 Subject: [PATCH 17/94] REVIEWED: Shader attribute/uniform default names can not be overriden #5925 --- src/config.h | 24 ++++++++------- src/rlgl.h | 85 ++++++++++++++++------------------------------------ 2 files changed, 40 insertions(+), 69 deletions(-) diff --git a/src/config.h b/src/config.h index 97f5ba544..cdb79a676 100644 --- a/src/config.h +++ b/src/config.h @@ -173,20 +173,22 @@ //#define RL_CULL_DISTANCE_FAR 4000.0 // Default projection matrix far cull distance // Default shader vertex attribute locations -//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0 -//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1 -//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2 -//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3 -//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4 -//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5 -//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6 -//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES 7 -//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8 +// NOTE: Locations can be redefined by user if required +//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0 +//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD 1 +//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL 2 +//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR 3 +//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT 4 +//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 5 +//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INDICES 6 +//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES 7 +//#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS 8 //#define RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM 9 // Default shader vertex attribute/uniform names to set location points // NOTE: When a new shader is loaded, locations are tried to be set for convenience, looking for the names defined here -// In case custom shader names are used, it's up to the user to set locations with GetShaderLocation*() functions +// WARNING: Location pre-defined names can not be changed, they are used by default shaders and all raylib examples shaders, they are just listed here for reference +// WARNING: In case custom shader names are used, it's up to the user to set locations with GetShaderLocation*() functions //#define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION //#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD //#define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL @@ -196,6 +198,7 @@ //#define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES "vertexBoneIndices" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES //#define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS //#define RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM "instanceTransform" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM + //#define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix //#define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix //#define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix @@ -203,6 +206,7 @@ //#define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView)) //#define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (tint color, multiplied by texture color) //#define RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES "boneMatrices" // bone matrices + //#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0) //#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1) //#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2) diff --git a/src/rlgl.h b/src/rlgl.h index 8c529a4e0..5e34f7bde 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -56,8 +56,8 @@ * #define RL_CULL_DISTANCE_NEAR 0.05 // Default projection matrix near cull distance * #define RL_CULL_DISTANCE_FAR 4000.0 // Default projection matrix far cull distance * -* When loading a shader, the following vertex attributes and uniform -* location names are tried to be set automatically: +* When loading a shader, the following vertex attributes and uniform location names are tried to be set automatically: +* WARNING: Pre-defined names can not be changed, they are used by default shaders and all raylib examples shaders, they are just listed here for reference * * #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION * #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD @@ -67,6 +67,8 @@ * #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 * #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES "vertexBoneIndices" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES * #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS +* #define RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM "instanceTransform" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM +* * #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix * #define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix * #define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix @@ -74,6 +76,7 @@ * #define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView))) * #define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color) * #define RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES "boneMatrices" // bone matrices +* * #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0) * #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1) * #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2) @@ -324,6 +327,7 @@ #define RL_DRAW_FRAMEBUFFER 0x8CA9 // GL_DRAW_FRAMEBUFFER // Default shader vertex attribute locations +// NOTE: Locations can be redefined by user if required #ifndef RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION #define RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION 0 #endif @@ -993,65 +997,28 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad #endif // Default shader vertex attribute names to set location points -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION - #define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD - #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL - #define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR - #define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT - #define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 - #define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES - #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES "vertexBoneIndices" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES -#endif -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS - #define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS -#endif +// WARNING: Pre-defined names can not be changed, they are used by default shaders and all raylib examples shaders, they are just listed here for reference +#define RL_DEFAULT_SHADER_ATTRIB_NAME_POSITION "vertexPosition" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_POSITION +#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD "vertexTexCoord" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD +#define RL_DEFAULT_SHADER_ATTRIB_NAME_NORMAL "vertexNormal" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_NORMAL +#define RL_DEFAULT_SHADER_ATTRIB_NAME_COLOR "vertexColor" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_COLOR +#define RL_DEFAULT_SHADER_ATTRIB_NAME_TANGENT "vertexTangent" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TANGENT +#define RL_DEFAULT_SHADER_ATTRIB_NAME_TEXCOORD2 "vertexTexCoord2" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_TEXCOORD2 +#define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEINDICES "vertexBoneIndices" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEINDICES +#define RL_DEFAULT_SHADER_ATTRIB_NAME_BONEWEIGHTS "vertexBoneWeights" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_BONEWEIGHTS +#define RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM "instanceTransform" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM -#ifndef RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM - #define RL_DEFAULT_SHADER_ATTRIB_NAME_INSTANCETRANSFORM "instanceTransform" // Bound by default to shader location: RL_DEFAULT_SHADER_ATTRIB_LOCATION_INSTANCETRANSFORM -#endif +#define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix +#define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix +#define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix +#define RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL "matModel" // model matrix +#define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView)) +#define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color) +#define RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES "boneMatrices" // bone matrices (required for GPU skinning) -#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_MVP - #define RL_DEFAULT_SHADER_UNIFORM_NAME_MVP "mvp" // model-view-projection matrix -#endif -#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW - #define RL_DEFAULT_SHADER_UNIFORM_NAME_VIEW "matView" // view matrix -#endif -#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION - #define RL_DEFAULT_SHADER_UNIFORM_NAME_PROJECTION "matProjection" // projection matrix -#endif -#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL - #define RL_DEFAULT_SHADER_UNIFORM_NAME_MODEL "matModel" // model matrix -#endif -#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL - #define RL_DEFAULT_SHADER_UNIFORM_NAME_NORMAL "matNormal" // normal matrix (transpose(inverse(matModelView)) -#endif -#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR - #define RL_DEFAULT_SHADER_UNIFORM_NAME_COLOR "colDiffuse" // color diffuse (base tint color, multiplied by texture color) -#endif -#ifndef RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 - #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0) -#endif -#ifndef RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 - #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1) -#endif -#ifndef RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 - #define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2) -#endif -#ifndef RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES - #define RL_DEFAULT_SHADER_UNIFORM_NAME_BONEMATRICES "boneMatrices" // bone matrices (required for GPU skinning) -#endif +#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE0 "texture0" // texture0 (texture slot active 0) +#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE1 "texture1" // texture1 (texture slot active 1) +#define RL_DEFAULT_SHADER_SAMPLER2D_NAME_TEXTURE2 "texture2" // texture2 (texture slot active 2) //---------------------------------------------------------------------------------- // Module Types and Structures Definition From 8999d2ba44d000d996c0a370452873a69d7ef242 Mon Sep 17 00:00:00 2001 From: Visen <48253336+VisenDev@users.noreply.github.com> Date: Wed, 1 Jul 2026 03:05:11 -0500 Subject: [PATCH 18/94] [tools] Add S-Expression Output Type to `rlparser` (#5943) * Add S-Expression output to rlparser.c * minor whitespace fix --- tools/rlparser/Makefile | 4 +- tools/rlparser/rlparser.c | 133 +++++++++++++++++++++++++++++++++++++- 2 files changed, 133 insertions(+), 4 deletions(-) diff --git a/tools/rlparser/Makefile b/tools/rlparser/Makefile index a645f7f41..a79900691 100644 --- a/tools/rlparser/Makefile +++ b/tools/rlparser/Makefile @@ -79,6 +79,7 @@ raylib_api: ../../src/raylib.h rlparser FORMAT=JSON EXTENSION=json $(MAKE) raylib_api.json FORMAT=XML EXTENSION=xml $(MAKE) raylib_api.xml FORMAT=LUA EXTENSION=lua $(MAKE) raylib_api.lua + FORMAT=SEXPR EXTENSION=sexpr $(MAKE) raylib_api.sexpr # rlparser execution: [raylib.h] parse, generating some output files raylib_api.$(EXTENSION): ../../src/raylib.h rlparser @@ -112,7 +113,8 @@ all: rlparser FORMAT=JSON EXTENSION=json $(MAKE) parse FORMAT=XML EXTENSION=xml $(MAKE) parse FORMAT=LUA EXTENSION=lua $(MAKE) parse + FORMAT=SEXPR EXTENSION=sexpr $(MAKE) parse # Clean rlparser and generated output files clean: - rm -f rlparser *.json *.txt *.xml *.lua + rm -f rlparser *.json *.txt *.xml *.lua *.sexpr diff --git a/tools/rlparser/rlparser.c b/tools/rlparser/rlparser.c index dc2afe114..a51b00b99 100644 --- a/tools/rlparser/rlparser.c +++ b/tools/rlparser/rlparser.c @@ -146,7 +146,7 @@ typedef struct FunctionInfo { } FunctionInfo; // Output format for parsed data -typedef enum { DEFAULT = 0, JSON, XML, LUA, CODE } OutputFormat; +typedef enum { DEFAULT = 0, JSON, XML, LUA, SEXPR, CODE } OutputFormat; //---------------------------------------------------------------------------------- // Global Variables Definition @@ -1062,6 +1062,7 @@ int main(int argc, char *argv[]) else if (outputFormat == JSON) printf("\nOutput format: JSON\n\n"); else if (outputFormat == XML) printf("\nOutput format: XML\n\n"); else if (outputFormat == LUA) printf("\nOutput format: LUA\n\n"); + else if (outputFormat == SEXPR) printf("\nOutput format: SEXPR\n\n"); else if (outputFormat == CODE) printf("\nOutput format: CODE\n\n"); ExportParsedData(outFileName, outputFormat); @@ -1098,10 +1099,10 @@ static void ShowCommandLineInfo(void) printf(" -i, --input : Define input header file to parse.\n"); printf(" NOTE: If not specified, defaults to: raylib.h\n\n"); printf(" -o, --output : Define output file and format.\n"); - printf(" Supported extensions: .txt, .json, .xml, .lua, .h\n"); + printf(" Supported extensions: .txt, .json, .xml, .lua, .sexpr, .h\n"); printf(" NOTE: If not specified, defaults to: raylib_api.txt\n\n"); printf(" -f, --format : Define output format for parser data.\n"); - printf(" Supported types: DEFAULT, JSON, XML, LUA, CODE\n\n"); + printf(" Supported types: DEFAULT, JSON, XML, LUA, SEXPR, CODE\n\n"); printf(" -d, --define : Define functions specifiers (i.e. RLAPI for raylib.h, RMAPI for raymath.h, etc.)\n"); printf(" NOTE: If no specifier defined, defaults to: RLAPI\n\n"); printf(" -t, --truncate : Define string to truncate input after (i.e. \"RLGL IMPLEMENTATION\" for rlgl.h)\n"); @@ -1154,6 +1155,7 @@ static void ProcessCommandLine(int argc, char *argv[]) else if (IsTextEqual(argv[i + 1], "JSON\0", 5)) outputFormat = JSON; else if (IsTextEqual(argv[i + 1], "XML\0", 4)) outputFormat = XML; else if (IsTextEqual(argv[i + 1], "LUA\0", 4)) outputFormat = LUA; + else if (IsTextEqual(argv[i + 1], "SEXPR\0", 4)) outputFormat = SEXPR; else if (IsTextEqual(argv[i + 1], "CODE\0", 5)) outputFormat = CODE; } else printf("WARNING: No format parameters provided\n"); @@ -2007,6 +2009,131 @@ static void ExportParsedData(const char *fileName, int format) fprintf(outFile, " }\n"); fprintf(outFile, "}\n"); } break; + case SEXPR: + { + fprintf(outFile, "("); + + // Print defines info + fprintf(outFile, "(defines\n"); + for (int i = 0; i < defineCount; i++) + { + if(i != 0) fprintf(outFile, "\n"); + fprintf(outFile, " ((name \"%s\")\n", defines[i].name); + fprintf(outFile, " (type \"%s\")\n", StrDefineType(defines[i].type)); + if ((defines[i].type == INT) || + (defines[i].type == LONG) || + (defines[i].type == FLOAT) || + (defines[i].type == DOUBLE) || + (defines[i].type == STRING)) + { + fprintf(outFile, " (value %s)\n", defines[i].value); + } + else + { + fprintf(outFile, " (value \"%s\")\n", defines[i].value); + } + fprintf(outFile, " (description \"%s\"))", defines[i].desc); + } + fprintf(outFile, ")\n\n"); + + // Print structs info + fprintf(outFile, " (structs\n"); + for (int i = 0; i < structCount; i++) + { + if(i != 0) fprintf(outFile, "\n\n"); + fprintf(outFile, " ((name \"%s\")\n", structs[i].name); + fprintf(outFile, " (description \"%s\")\n", EscapeBackslashes(structs[i].desc)); + fprintf(outFile, " (fields "); + for (int f = 0; f < structs[i].fieldCount; f++) + { + fprintf(outFile, "\n ((type \"%s\")\n", structs[i].fieldType[f]); + fprintf(outFile, " (name \"%s\")\n", structs[i].fieldName[f]); + fprintf(outFile, " (description \"%s\"))", EscapeBackslashes(structs[i].fieldDesc[f])); + } + fprintf(outFile, "))"); + } + fprintf(outFile, ")\n\n"); + + // Print aliases info + fprintf(outFile, " (aliases\n"); + for (int i = 0; i < aliasCount; i++) + { + if(i != 0) fprintf(outFile, "\n\n"); + fprintf(outFile, " ((type \"%s\")\n", aliases[i].type); + fprintf(outFile, " (name \"%s\")\n", aliases[i].name); + fprintf(outFile, " (description \"%s\"))", aliases[i].desc); + } + fprintf(outFile, ")\n\n"); + + // Print enums info + fprintf(outFile, " (enums\n"); + for (int i = 0; i < enumCount; i++) + { + if(i != 0) fprintf(outFile, "\n\n"); + fprintf(outFile, " ((name \"%s\")\n", enums[i].name); + fprintf(outFile, " (description \"%s\")\n", EscapeBackslashes(enums[i].desc)); + fprintf(outFile, " (values\n"); + for (int e = 0; e < enums[i].valueCount; e++) + { + if(e != 0) fprintf(outFile, "\n\n"); + fprintf(outFile, " ((name \"%s\")\n", enums[i].valueName[e]); + fprintf(outFile, " (value %i)\n", enums[i].valueInteger[e]); + fprintf(outFile, " (description \"%s\"))", EscapeBackslashes(enums[i].valueDesc[e])); + } + fprintf(outFile, "))"); + } + fprintf(outFile, ")\n\n"); + + // Print callbacks info + fprintf(outFile, " (callbacks\n"); + for (int i = 0; i < callbackCount; i++) + { + if(i != 0) fprintf(outFile, "\n\n"); + fprintf(outFile, " ((name \"%s\")\n", callbacks[i].name); + fprintf(outFile, " (description \"%s\")\n", EscapeBackslashes(callbacks[i].desc)); + fprintf(outFile, " (return-type \"%s\")", callbacks[i].retType); + + if (callbacks[i].paramCount == 0) fprintf(outFile, "\n"); + else + { + fprintf(outFile, "\n (params\n"); + for (int p = 0; p < callbacks[i].paramCount; p++) + { + if(p != 0) fprintf(outFile, "\n"); + fprintf(outFile, " ((type \"%s\") (name \"%s\"))", callbacks[i].paramType[p], callbacks[i].paramName[p]); + } + fprintf(outFile, ")"); + } + fprintf(outFile, ")"); + } + fprintf(outFile, ")\n\n"); + + // Print functions info + fprintf(outFile, " (functions\n"); + for (int i = 0; i < funcCount; i++) + { + if(i != 0) fprintf(outFile, "\n\n"); + fprintf(outFile, " ((name \"%s\")\n", funcs[i].name); + fprintf(outFile, " (description \"%s\")\n", EscapeBackslashes(funcs[i].desc)); + fprintf(outFile, " (return-type \"%s\")", funcs[i].retType); + + if (funcs[i].paramCount == 0) fprintf(outFile, ""); + else + { + fprintf(outFile, "\n (params\n"); + for (int p = 0; p < funcs[i].paramCount; p++) + { + if(p != 0) fprintf(outFile, "\n"); + fprintf(outFile, " ((type \"%s\") (name \"%s\"))", funcs[i].paramType[p], funcs[i].paramName[p]); + } + fprintf(outFile, ")"); + } + fprintf(outFile, ")"); + } + fprintf(outFile, ")"); + fprintf(outFile, ")\n"); + } break; + case CODE: default: break; } From 04a269f4f850a2f1179fed3a5ccc16923d9f396a Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 1 Jul 2026 11:55:27 +0200 Subject: [PATCH 19/94] ADDED: Support for .pep image fileformat, useful for pixl-art --- src/config.h | 3 + src/external/pep.h | 1328 ++++++++++++++++++++++++++++++++++++++++++++ src/rtextures.c | 53 ++ 3 files changed, 1384 insertions(+) create mode 100644 src/external/pep.h diff --git a/src/config.h b/src/config.h index cdb79a676..e77089b68 100644 --- a/src/config.h +++ b/src/config.h @@ -244,6 +244,9 @@ #ifndef SUPPORT_FILEFORMAT_QOI #define SUPPORT_FILEFORMAT_QOI 1 #endif +#ifndef SUPPORT_FILEFORMAT_PEP + #define SUPPORT_FILEFORMAT_PEP 0 +#endif #ifndef SUPPORT_FILEFORMAT_PSD #define SUPPORT_FILEFORMAT_PSD 0 // Disabled by default #endif diff --git a/src/external/pep.h b/src/external/pep.h new file mode 100644 index 000000000..bc8a793b1 --- /dev/null +++ b/src/external/pep.h @@ -0,0 +1,1328 @@ +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Prediction-Encoded Pixels (pep) +// +// author(s): +// ENDESGA - https://x.com/ENDESGA | https://bsky.app/profile/endesga.bsky.social +// +// contributer(s): +// Mariusz Dzikowski - https://github.com/demurzasty +// Akreson - https://github.com/Akreson +// Alepacho - https://github.com/Alepacho +// +// https://github.com/ENDESGA/pep +// 2026 - CC0 - FOSS forever +// + +// The .pep type is a pixel art format made to compress as small as possible. +// It uses a custom "Prediction by Partial Matching" compression method +// designed from the ground up for palettized pixel art. + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma region - DEPENDENCIES +// + +#pragma once + +#ifndef _GNU_SOURCE + #define _GNU_SOURCE +#endif + +#include // uint*_t +#include // mem-alloc +#include // FILE +#include // memset + +#pragma endregion dependencies + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma region - MACROS +// + +#define __PEP_STRINGIFY( VALUE ) #VALUE +#define _PEP_STRINGIFY( VALUE ) __PEP_STRINGIFY( VALUE ) + +//////////////////////////////////////////////////////////////// +#pragma region - memory + +// This defines a set of macros that serve as wrappers for the standard +// C library memory management functions: `malloc`, `realloc`, and `free`. +// These macros can be used to easily replace the underlying memory allocation +// implementation in a project, for example, with a custom allocator or a +// debug-enabled version, without modifying all call sites. +#ifndef PEP_MALLOC + #define PEP_MALLOC( size ) malloc( size ) + #define PEP_REALLOC( ptr, size ) realloc( ptr, size ) + #define PEP_FREE( ptr ) free( ptr ) +#endif + +#pragma endregion memory + +//////////////////////////////////////////////////////////////// +#pragma region - bits + +// Provides a cross-platform macro to count leading zeros in a 32-bit integer. +#ifndef PEP_COUNT_LEADING_ZEROS + #ifdef _MSC_VER + // Microsoft Visual C++ compiler. + #define PEP_COUNT_LEADING_ZEROS( x ) __lzcnt( x ) + #else + // GCC/Clang compilers. + #define PEP_COUNT_LEADING_ZEROS( x ) __builtin_clz( x ) + #endif +#endif + +// How many bits do we need to fit N values? +#define PEP_BITS_TO_FIT( N ) ( ( ( N ) <= 1 ) ? 1 : ( 32 - PEP_COUNT_LEADING_ZEROS( ( N ) - 1 ) ) ) + +#pragma endregion bits + +//////////////////////////////////////////////////////////////// +#pragma region - hash + +// Standard hash multipliers, there might be better ones: +#define _PEP_HASH_N 1540483477u // 0x5BD1E995 MurmurHash2 +#define _PEP_HASH_W 3332679571u // 0xC6A4A793 MurmurHash64A +#define _PEP_HASH_NW 3432918353u // 0xCC9E2D51 MurmurHash3 +#define _PEP_HASH_NE 2246822507u // 0x85EBCA6B MurmurHash3 +// Hash-prospector, avalanche-optimized, by Chris Wellons: +#define _PEP_HASH_NN 2146121005u // 0x7FEB352D lowbias32 +#define _PEP_HASH_WW 2890668881u // 0xAC4C1B51 triple32 round-2 +#define _PEP_HASH_NNW 830770091u // 0x31848BAB triple32 round-3 +#define _PEP_HASH_NNE 1935289751u // 0x735A2D97 prospector +#define _PEP_HASH_NWW 2943497623u // 0xAF723597 prospector + +#pragma endregion hash + +#pragma endregion macros + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma region - CONSTANTS +// + +#define PEP_NAME "pep" + +//////////////////////////////////////////////////////////////// +#pragma region - version + +#define PEP_VERSION_MAJOR 0 +#define PEP_VERSION_MINOR 6 +#define PEP_VERSION_PATCH 0 +#define PEP_VERSION _PEP_STRINGIFY( PEP_VERSION_MAJOR ) "." _PEP_STRINGIFY( PEP_VERSION_MINOR ) "." _PEP_STRINGIFY( PEP_VERSION_PATCH ) + +#pragma endregion version + +//////////////////////////////////////////////////////////////// +#pragma region - frequency + +// This is the amount of frequencies per context, and the amount of contexts, +// with [256] being the order0 context. +// Originally there were 256*256 contexts, but I found the image didn't get +// much bigger with the same amount of frequencies. Theoretically the more +// contexts you have the smaller the image is... +#define PEP_FREQ_N 257 +#define PEP_FREQ_END ( PEP_FREQ_N - 1 ) +#define PEP_CONTEXTS_MAX PEP_FREQ_END + +// PEP_FREQ_MAX is the maximum accumulative frequency. +// This is the starting maximum, and is scaled as the image compresses, via +// the palette-delta; which seems to roughly correlate with the complexity. +// This value works better for low-res images. +#define PEP_FREQ_MAX ( PEP_FREQ_END >> 1 ) + +#pragma endregion frequency + +//////////////////////////////////////////////////////////////// +#pragma region - arithmetic -coding + +// These constants are for the 63bit arithmetic-coding, specifically not 64bit +// because of overflow. +#define PEP_CODE_BITS 24lu +#define PEP_CODE_BITS_INV ( 32lu - PEP_CODE_BITS ) +#define PEP_FREQ_MAX_BITS 14lu +#define PEP_PROB_MAX_VALUE ( 1 << PEP_FREQ_MAX_BITS ) +#define PEP_CODE_MAX_VALUE ( ( 1 << PEP_CODE_BITS ) - 1 ) + +#pragma endregion arithmetic -coding + +#pragma endregion defaults + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma region - DECLARATIONS +// + +//////////////////////////////////////////////////////////////// +#pragma region - formats + +// .pep can automatically convert from RGBA to BGRA (little/big endian), +// which is often for low-level/backend rendering pipelines. +// Windows only supports ARGB for example, and so sometimes it's easier to +// make the whole application use that format. +typedef enum +{ + pep_rgba, + pep_bgra, + + pep_abgr, + pep_argb +} +pep_format; + +// Palette colors can be restricted in the serialization phase to a maximum +// amount of bits per channel. +// The default is 8 bits per channel (standard 32 bit colors). +// This is NOT bits-per-pixel and does NOT cap palette_size. +typedef enum +{ + pep_1bit, + pep_2bit, + pep_4bit, + pep_8bit +} +pep_channel_bits; + +#pragma endregion formats + +//////////////////////////////////////////////////////////////// +#pragma region - arithmetic -coding + +// During the compression process the context per frequency-group needs to be +// tracked, with the sum of all frequencies being stored. +typedef struct +{ + uint16_t freq[ PEP_FREQ_N ]; + uint32_t sum; +} +_pep_context; + +// Arithmetic coding structures: +typedef struct +{ + uint8_t* data_ref; + uint32_t low; + uint32_t range; +} +_pep_ac_encode; + +typedef struct +{ + uint8_t* data_ref; + uint8_t* end_of_data; + uint32_t low; + uint32_t range; + uint32_t code; +} +_pep_ac_decode; + +typedef struct +{ + uint32_t high; + uint32_t low; + uint32_t scale; +} +_pep_prob; + +typedef struct +{ + _pep_prob prob; + uint32_t symbol; +} +_pep_sym_decode; + +#pragma endregion arithmetic -coding + +//////////////////////////////////////////////////////////////// +#pragma region - pep + +// This is the main struct-type that contains values for using this format. +// +// `channel_bits` controls how many bits each R/G/B/A component of every +// palette entry is quantized to during serialization. It does NOT limit +// the number of palette entries (that's `palette_size`, up to 256). +// For example, pep_2bit means each channel has 4 possible values (0/85/170/255), +// so the palette can only draw from 4*4*4 = 64 distinct RGB colors. +typedef struct +{ + uint8_t* bytes; + uint64_t bytes_size; + uint16_t width; + uint16_t height; + pep_format format; + uint32_t palette[ 256 ]; + uint8_t palette_size; + pep_channel_bits channel_bits; + uint8_t model; +} +pep; + +#pragma endregion pep + +//////////////////////////////////////////////////////////////// +#pragma region - functions + +pep pep_compress( const uint32_t* in_pixels, const uint16_t width, const uint16_t height, const pep_format in_format, const pep_channel_bits in_channel_bits ); +uint32_t* pep_decompress( const pep* const in_pep, const pep_format out_format, const uint8_t first_color_transparent, uint8_t const pre_multiply ); +void pep_free( pep* in_pep ); +uint8_t* pep_serialize( const pep* in_pep, uint32_t* const out_size ); +pep pep_deserialize( const uint8_t* const in_bytes, const uint32_t in_bytes_size ); +uint8_t pep_save( const pep* const in_pep, const char* const file_path ); +pep pep_load( const char* const file_path ); + +#pragma endregion functions + +#pragma endregion declarations + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +#pragma region - DEFINITIONS +// + +#ifdef PEP_IMPLEMENTATION + +#pragma region - private / functions + +static _pep_prob _pep_get_prob_from_context( const _pep_context* const context, const uint32_t symbol ); +static void _pep_arith_encode( _pep_ac_encode* const ac, const _pep_prob prob ); +static void _pep_arith_encode_normalize( _pep_ac_encode* const ac ); +static uint32_t _pep_arith_decode_curr_freq( _pep_ac_decode* const ac, const uint32_t scale ); +static void _pep_arith_decode_update( _pep_ac_decode* const ac, const _pep_prob prob ); +static _pep_sym_decode _pep_get_sym_from_freq( const _pep_context* const context, const uint32_t target_freq ); +static uint32_t _pep_pre_multiply( const uint32_t pixel, const pep_format format ); +static uint32_t _pep_reformat( const uint32_t in_color, const pep_format in_format, const pep_format out_format ); + +#pragma endregion private / functions + +#ifdef _MSC_VER + // Intrin header is only needed for implementation. + #include // __lzcnt + + // Disable unsafe fopen usage warning on MSVC compiler. + #pragma warning( push ) + #pragma warning( disable : 4996 ) +#endif + +//////////////////////////////////////////////////////////////// +#pragma region - arithmetic + +//////////////////////////////// +#pragma region | encode + +// Getting cumulative frequnce of symbol +static _pep_prob _pep_get_prob_from_context( const _pep_context* const context, const uint32_t symbol ) +{ + _pep_prob prob = { 0 }; + prob.scale = context->sum; + + for( uint32_t index = 0; index < symbol; ++index ) + { + prob.low += context->freq[ index ]; + } + + prob.high = prob.low + context->freq[ symbol ]; + return prob; +} + +// This encodes a symbol into the arithmetic-coding range. It scales the +// current range based on the symbol's frequency and total frequency count. +static void _pep_arith_encode( _pep_ac_encode* const ac, const _pep_prob prob ) +{ + ac->range /= prob.scale; + ac->low += prob.low * ac->range; + ac->range *= prob.high - prob.low; +} + +// Adjusts the arithmetic-coding range by removing a boundary value +// Main goal of this process is to keep our range from getting +// too small. +static void _pep_arith_encode_normalize( _pep_ac_encode* const ac ) +{ + while( 1 ) + { + if( ( ac->low ^ ( ac->low + ac->range ) ) >= PEP_CODE_MAX_VALUE ) + { + if( ac->range >= PEP_PROB_MAX_VALUE ) break; + + ac->range = PEP_PROB_MAX_VALUE - ( ac->low & ( PEP_PROB_MAX_VALUE - 1 ) ); + } + + uint8_t byte = ac->low >> PEP_CODE_BITS; + ac->low <<= PEP_CODE_BITS_INV; + ac->range <<= PEP_CODE_BITS_INV; + *ac->data_ref++= byte; + } +} + +#pragma endregion encode + +//////////////////////////////// +#pragma region | decode + +// Getting current frequency by doing reverse trasformation +static uint32_t _pep_arith_decode_curr_freq( _pep_ac_decode* const ac, const uint32_t scale ) +{ + ac->range /= scale; + uint32_t result = ( ac->code - ac->low ) / ( ac->range ); + return result; +} + +// Same as with the encode_normalize, only on decode we reading in value +static void _pep_arith_decode_update( _pep_ac_decode* const ac, const _pep_prob prob ) +{ + ac->low += ac->range * prob.low; + ac->range *= prob.high - prob.low; + + while( 1 ) + { + if( ( ac->low ^ ( ac->low + ac->range ) ) >= PEP_CODE_MAX_VALUE ) + { + if( ac->range < PEP_PROB_MAX_VALUE ) + { + ac->range = PEP_PROB_MAX_VALUE - ( ac->low & ( PEP_PROB_MAX_VALUE - 1 ) ); + } + else break; + } + + uint8_t in_byte = 0; + if( ac->data_ref != ac->end_of_data ) + { + in_byte = *ac->data_ref++; + } + + ac->code = ( ac->code << 8 ) | in_byte; + ac->range <<= 8; + ac->low <<= 8; + } +} + +static _pep_sym_decode _pep_get_sym_from_freq( const _pep_context* const context, const uint32_t target_freq ) +{ + _pep_sym_decode result = { 0 }; + + uint32_t s = 0; + uint32_t freq = 0; + for( ; s <= PEP_FREQ_END; ++s ) + { + freq += context->freq[ s ]; + if( freq > target_freq ) break; + } + if( s > PEP_FREQ_END ) s = PEP_FREQ_END; + + result.prob.high = freq; + result.prob.low = freq - context->freq[ s ]; + result.prob.scale = context->sum; + result.symbol = s; + + return result; +} + +#pragma endregion decode + +#pragma endregion arithmetic + +//////////////////////////////////////////////////////////////// +#pragma region - compression + +//////////////////////////////// +#pragma region | compression / hidden + +// pep supports pre-multiplying the RGB channels with the A channel. +static uint32_t _pep_pre_multiply( const uint32_t pixel, const pep_format format ) +{ + uint8_t* bytes = ( uint8_t* )( &pixel ); + + if( format <= pep_bgra ) + { + uint32_t scaled_a = ( uint32_t )( bytes[ 3 ] ) * 257; + bytes[ 1 ] = ( uint8_t )( ( ( uint32_t )( bytes[ 1 ] ) * scaled_a + 32896 ) >> 16 ); + bytes[ 2 ] = ( uint8_t )( ( ( uint32_t )( bytes[ 2 ] ) * scaled_a + 32896 ) >> 16 ); + bytes[ 3 ] = ( uint8_t )( ( ( uint32_t )( bytes[ 3 ] ) * scaled_a + 32896 ) >> 16 ); + } + else + { + uint32_t scaled_a = ( uint32_t )( bytes[ 0 ] ) * 257; + bytes[ 0 ] = ( uint8_t )( ( ( uint32_t )( bytes[ 0 ] ) * scaled_a + 32896 ) >> 16 ); + bytes[ 1 ] = ( uint8_t )( ( ( uint32_t )( bytes[ 1 ] ) * scaled_a + 32896 ) >> 16 ); + bytes[ 2 ] = ( uint8_t )( ( ( uint32_t )( bytes[ 2 ] ) * scaled_a + 32896 ) >> 16 ); + } + + return pixel; +} + +// pep supports "dynamic formats", where you can specify what the in-bytes are, +// and reformat to a different channel-order. +// This means two "identical" pep files can have different formats, but you +// can choose how to reformat it when it decompresses! +static uint32_t _pep_reformat( const uint32_t in_color, const pep_format in_format, const pep_format out_format ) +{ + if( in_format == out_format ) return in_color; + + if( in_format <= pep_bgra && out_format <= pep_bgra ) + { // RGBA <-> BGRA: swap R and B + return( in_color & 0xff00ff00 ) | ( ( in_color & 0x000000ff ) << 16 ) | ( ( in_color & 0x00ff0000 ) >> 16 ); + } + else if( in_format >= pep_abgr && out_format >= pep_abgr ) + { // ABGR <-> ARGB: swap R and B + return( in_color & 0x00ff00ff ) | ( ( in_color & 0x0000ff00 ) << 16 ) | ( ( in_color & 0xff000000 ) >> 16 ); + } + else if( ( in_format ^ out_format ) == 2 ) + { // Alpha flip: RGBA <-> ARGB or BGRA <-> ABGR + return( ( in_color & 0x000000ff ) << 24 ) | ( ( in_color & 0x0000ff00 ) << 8 ) | ( ( in_color & 0x00ff0000 ) >> 8 ) | ( ( in_color & 0xff000000 ) >> 24 ); + } + else if( in_format < out_format ) + { // Flip: RGBA/BGRA -> ABGR/ARGB + return( ( in_color & 0xff000000 ) >> 24 ) | ( ( in_color & 0x00ffffff ) << 8 ); + } + else + { // Flip: ABGR/ARGB -> RGBA/BGRA + return( ( in_color & 0x000000ff ) << 24 ) | ( ( in_color & 0xffffff00 ) >> 8 ); + } +} + +// Update the frequency table after encoding/decoding a symbol. +// This increments the symbol's frequency and the total sum. +// When we hit freq_max, we increase the freq_max via a complexity +// approximation via the palette-size, then we scale everything down +// to a quarter to keep the frequencies manageable. +// This dynamic part helps the compression adapt to the image's patterns. +#define _PEP_UPDATE( CONTEXT, SYMBOL, FREQ_MAX, PALETTE_SIZE )\ + do\ + {\ + CONTEXT->freq[ SYMBOL ] += 2;\ + CONTEXT->sum += 2;\ + if( CONTEXT->freq[ SYMBOL ] >= FREQ_MAX || CONTEXT->sum >= PEP_PROB_MAX_VALUE )\ + {\ + FREQ_MAX += ( PEP_FREQ_END - PALETTE_SIZE ) >> 1;\ + CONTEXT->sum = 0;\ + for( uint64_t f = 0; f < PEP_FREQ_N; f++ )\ + {\ + const uint16_t _f = CONTEXT->freq[ f ];\ + if( _f == 0 ) continue;\ + const uint16_t scaled = ( _f + 1 ) >> 1;\ + CONTEXT->freq[ f ] = scaled;\ + CONTEXT->sum += scaled;\ + }\ + }\ + }\ + while( 0 ) + +#pragma endregion hidden + +//////////////////////////////// +#pragma region | compression / visible + +#define PEP_HASH_BIT_CONTEXT ( 1u << 16 ) + +enum +{ + _PEP_TAP_HASH, + _PEP_TAP_NW, + _PEP_TAP_W +}; + +// Different context models perform differently depending on the pixel data. +// From lots of testing it seems these 3 structures give the best results +// across the 3 major types of pixel art. +// Pep will sacrifice some time to ensure the file is as small as possible +// by testing all 3 of these without assumptions. +static const int8_t _pep_models[] = + { + _PEP_TAP_HASH, // typically for ~2 colors + _PEP_TAP_NW, // typically for ~4-8 colors + _PEP_TAP_W // typically for >=64 colors + }; +#define PEP_NUM_MODELS ( ( uint8_t )( sizeof( _pep_models ) / sizeof( _pep_models[ 0 ] ) ) ) + +typedef struct +{ + _pep_context* contexts; + uint32_t index_end; + uint32_t index_escape; + int8_t kind; +} +_pep_model_context; + +// Allocate only the context regions a given model uses, then seed order-0. +static uint8_t _pep_model_init( _pep_model_context* m, int8_t kind, uint32_t pcount ) +{ + memset( m, 0, sizeof( *m ) ); + m->kind = kind; + m->index_escape = pcount; + m->index_end = pcount + 1; + + // order0 starts at offset 0, followed by the specific context level + uint32_t off = 1; + switch( kind ) + { + case _PEP_TAP_HASH: + { + off += PEP_HASH_BIT_CONTEXT; + break; + } + case _PEP_TAP_NW: + { + off += m->index_end * m->index_end; + break; + } + case _PEP_TAP_W: + { + off += m->index_end; + break; + } + } + + m->contexts = ( _pep_context* )calloc( off, sizeof( _pep_context ) ); + if( !m->contexts ) return 0; + + _pep_context* order0 = &m->contexts[ 0 ]; + for( uint32_t index = 0; index < pcount; index++ ) order0->freq[ index ] = 1; + order0->sum = pcount; + return 1; +} + +static void _pep_model_free( _pep_model_context* m ) +{ + if( m->contexts ) + { + free( m->contexts ); + m->contexts = NULL; + } +} + +// Resolve the context pointer for the specific level of this pixel. +static _pep_context* _pep_build_level( const _pep_model_context* m, const uint8_t* idx, uint32_t pos, uint32_t x, uint32_t y, uint16_t width ) +{ + // It's only possible to tap previous values: + /* + - NNW NN NNE + NWW NW N NE + WW W [x] + */ + // The 10th NNWW tap has dimishing returns + + const uint32_t SENT = m->index_escape; + const uint32_t index_end = m->index_end; + const uint32_t Wv = ( x > 0 ) ? idx[ pos - 1 ] : SENT; + const uint32_t Nv = ( y > 0 ) ? idx[ pos - width ] : SENT; + + switch( m->kind ) + { + case _PEP_TAP_HASH: + { + const uint32_t NWv = ( x > 0 && y > 0 ) ? idx[ pos - width - 1 ] : SENT; + const uint32_t NNv = ( y > 1 ) ? idx[ pos - 2 * width ] : SENT; + const uint32_t WWv = ( x > 1 ) ? idx[ pos - 2 ] : SENT; + const uint32_t NEv = ( ( x + 1 ) < width && y > 0 ) ? idx[ pos - width + 1 ] : SENT; + const uint32_t NNWv = ( y > 1 && x > 0 ) ? idx[ pos - 2 * width - 1 ] : SENT; + const uint32_t NNEv = ( y > 1 && ( x + 1 ) < width ) ? idx[ pos - 2 * width + 1 ] : SENT; + const uint32_t NWWv = ( x > 1 && y > 0 ) ? idx[ pos - width - 2 ] : SENT; + + uint32_t h = Nv * _PEP_HASH_N + Wv * _PEP_HASH_W + NWv * _PEP_HASH_NW + NEv * _PEP_HASH_NE + NNv * _PEP_HASH_NN + WWv * _PEP_HASH_WW + NNWv * _PEP_HASH_NNW + NNEv * _PEP_HASH_NNE + NWWv * _PEP_HASH_NWW; + h ^= h >> 15; + return &m->contexts[ 1 + ( h & ( PEP_HASH_BIT_CONTEXT - 1 ) ) ]; + } + case _PEP_TAP_NW: + { + return &m->contexts[ 1 + Nv * index_end + Wv ]; + } + case _PEP_TAP_W: + { + return &m->contexts[ 1 + Wv ]; + } + } + return NULL; +} + +// Encode all pixels with one model and return the size of the byte stream. +static uint64_t _pep_encode_model( const uint8_t* idx, uint16_t width, uint16_t height, uint32_t pcount, uint8_t model, uint8_t* out ) +{ + _pep_model_context m; + if( !_pep_model_init( &m, _pep_models[ model ], pcount ) ) return 0; + const uint32_t index_escape = m.index_escape; + + _pep_ac_encode ac = { 0 }; + ac.range = ( uint32_t )( ( 1llu << 32 ) - 1 ); + ac.data_ref = out; + uint16_t freq_max = PEP_FREQ_MAX; + _pep_context* order0 = &m.contexts[ 0 ]; + + uint32_t pos = 0; + for( uint32_t y = 0; y < height; y++ ) + { + for( uint32_t x = 0; x < width; x++, pos++ ) + { + const uint32_t symbol = idx[ pos ]; + _pep_context* context = _pep_build_level( &m, idx, pos, x, y, width ); + uint8_t encoded_in_level = 0; + + if( context->sum != 0 ) + { + if( context->freq[ symbol ] != 0 ) + { + _pep_prob prob = _pep_get_prob_from_context( context, symbol ); + _pep_arith_encode( &ac, prob ); + _pep_arith_encode_normalize( &ac ); + _PEP_UPDATE( context, symbol, freq_max, pcount ); + encoded_in_level = 1; + } + else + { + _pep_prob prob = _pep_get_prob_from_context( context, index_escape ); + _pep_arith_encode( &ac, prob ); + _pep_arith_encode_normalize( &ac ); + context->freq[ index_escape ] += 1; + context->sum += 1; + } + } + + if( !encoded_in_level ) + { + _pep_prob prob = _pep_get_prob_from_context( order0, symbol ); + _pep_arith_encode( &ac, prob ); + _pep_arith_encode_normalize( &ac ); + _PEP_UPDATE( order0, symbol, freq_max, pcount ); + + if( context->sum == 0 ) + { + context->freq[ index_escape ] = 1; + context->sum = 1; + } + context->freq[ symbol ] = 1; + context->sum += 1; + } + } + } + + for( uint8_t index = 0; index < 4; index++ ) + { + uint8_t byte = ac.low >> PEP_CODE_BITS; + ac.low <<= PEP_CODE_BITS_INV; + *ac.data_ref++= byte; + } + + uint64_t size = ( uint64_t ) ( ac.data_ref - out ); + _pep_model_free( &m ); + return size; +} + +// The format of the in_pixels has to be the same as in_format. +// out_format is the one applied to the newly compressed pep + +// Compresses raw pixels into a pep, trying each context model and keeping the +// smallest result (the winning model index is stored in out.model). +pep pep_compress( const uint32_t* in_pixels, const uint16_t width, const uint16_t height, const pep_format in_format, const pep_channel_bits in_channel_bits ) +{ + pep out_pep = { 0 }; + uint32_t area = ( uint32_t )width * height; + if( in_pixels == NULL || area == 0 ) return out_pep; + + out_pep.width = width; + out_pep.height = height; + out_pep.format = in_format; + out_pep.channel_bits = in_channel_bits; + + uint8_t* idx = ( uint8_t* )PEP_MALLOC( area ); + + uint32_t palette[ 256 ]; + uint16_t count = 0; // 1-256 distinct colours + const uint32_t* p = in_pixels; + const uint32_t* p_end = p + area; + uint32_t last_p = 0, + this_p = 0; + while( p < p_end ) + { + this_p = *p; + if( p > in_pixels && this_p == last_p ) + { + p++; + continue; + } + uint16_t n = 0; + while( n < count && this_p != palette[ n ] ) n++; + if( n >= count && count < 256 ) palette[ count++ ] = this_p; + last_p = this_p; + p++; + } + memcpy( out_pep.palette, palette, ( size_t ) count * sizeof( uint32_t ) ); + out_pep.palette_size = ( uint8_t )count; + for( uint32_t index = 0; index < area; index++ ) + { + uint32_t c = in_pixels[ index ]; + uint16_t k = 0; + while( k < count && palette[ k ] != c ) k++; + idx[ index ] = ( uint8_t )( k < count ? k : 0 ); + } + const uint32_t pcount = out_pep.palette_size ? out_pep.palette_size : 256; + + uint8_t* best = ( uint8_t* )PEP_MALLOC( ( size_t ) area * sizeof( uint32_t ) + 64 ); + uint8_t* tmp = ( uint8_t* )PEP_MALLOC( ( size_t ) area * sizeof( uint32_t ) + 64 ); + uint64_t best_size = 0; + uint8_t best_model = 0; + + for( uint8_t model = 0; model < PEP_NUM_MODELS; model++ ) + { + uint64_t size = _pep_encode_model( idx, width, height, pcount, model, tmp ); + if( size == 0 ) continue; + + if( best_size == 0 || size < best_size ) + { + best_size = size; + best_model = model; + memcpy( best, tmp, size ); + } + } + + out_pep.bytes = ( uint8_t* )PEP_REALLOC( best, best_size ); + out_pep.bytes_size = best_size; + out_pep.model = ( uint8_t )best_model; + + PEP_FREE( tmp ); + PEP_FREE( idx ); + return out_pep; +} + +// Decode all pixels with one model (mirror of _pep_encode_model). +static void _pep_decode_model( const uint8_t* in_bytes, uint64_t in_size, uint16_t width, uint16_t height, uint32_t pcount, uint8_t model, const uint32_t* palette, pep_format in_format, pep_format out_format, uint8_t pre_multiply, uint8_t* idx, uint32_t* out_pixels ) +{ + _pep_model_context m; + if( !_pep_model_init( &m, _pep_models[ model ], pcount ) ) return; + const uint32_t index_escape = m.index_escape; + + _pep_ac_decode ac = { 0 }; + ac.range = ( uint32_t )( ( 1llu << 32 ) - 1 ); + ac.data_ref = ( uint8_t* )in_bytes; + ac.end_of_data = ( uint8_t* )in_bytes + in_size; + for( uint8_t index = 0; index < 4; ++index ) + { + uint8_t b = 0; + if( ac.data_ref != ac.end_of_data ) b = *ac.data_ref++; + ac.code = ( ac.code << 8 ) | b; + } + + uint16_t freq_max = PEP_FREQ_MAX; + _pep_context* order0 = &m.contexts[ 0 ]; + uint32_t pos = 0; + + for( uint32_t y = 0; y < height; y++ ) + { + for( uint32_t x = 0; x < width; x++, pos++ ) + { + _pep_context* context = _pep_build_level( &m, idx, pos, x, y, width ); + uint32_t symbol = 0; + uint8_t decoded_in_level = 0; + + if( context->sum != 0 ) + { + uint32_t f = _pep_arith_decode_curr_freq( &ac, context->sum ); + _pep_sym_decode r = _pep_get_sym_from_freq( context, f ); + _pep_arith_decode_update( &ac, r.prob ); + + if( r.symbol != index_escape ) + { + symbol = r.symbol; + _PEP_UPDATE( context, symbol, freq_max, pcount ); + decoded_in_level = 1; + } + else + { + context->freq[ index_escape ] += 1; + context->sum += 1; + } + } + + if( !decoded_in_level ) + { + uint32_t f = _pep_arith_decode_curr_freq( &ac, order0->sum ); + _pep_sym_decode r = _pep_get_sym_from_freq( order0, f ); + _pep_arith_decode_update( &ac, r.prob ); + symbol = r.symbol; + _PEP_UPDATE( order0, symbol, freq_max, pcount ); + + if( context->sum == 0 ) + { + context->freq[ index_escape ] = 1; + context->sum = 1; + } + context->freq[ symbol ] = 1; + context->sum += 1; + } + + idx[ pos ] = ( uint8_t )symbol; + uint32_t pixel = ( symbol < pcount ) ? _pep_reformat( palette[ symbol ], in_format, out_format ) : 0; + if( pre_multiply != 0 ) pixel = _pep_pre_multiply( pixel, out_format ); + out_pixels[ pos ] = pixel; + } + } + _pep_model_free( &m ); +} + +uint32_t* pep_decompress( const pep* const in_pep, const pep_format out_format, const uint8_t transparent_first_color, uint8_t const pre_multiply ) +{ + if( in_pep == NULL ) return NULL; + if( in_pep->bytes == NULL || in_pep->bytes_size == 0 || in_pep->width == 0 || in_pep->height == 0 ) return NULL; + + const uint16_t width = in_pep->width, + height = in_pep->height; + const uint32_t area = ( uint32_t )width * height; + uint32_t* out_pixels = ( uint32_t* )PEP_MALLOC( area * sizeof( uint32_t ) ); + uint8_t* idx = ( uint8_t* )PEP_MALLOC( area ); + + const uint32_t pcount = in_pep->palette_size ? in_pep->palette_size : 256; + static uint32_t palette[ 256 ]; + memcpy( palette, in_pep->palette, pcount * sizeof( uint32_t ) ); + if( transparent_first_color != 0 ) + { + if( in_pep->format <= pep_bgra ) palette[ 0 ] &= 0x00ffffff; + else palette[ 0 ] &= 0xffffff00; + } + + uint8_t model = in_pep->model; + if( model >= PEP_NUM_MODELS ) model = 0; + + _pep_decode_model( in_pep->bytes, in_pep->bytes_size, width, height, pcount, model, palette, in_pep->format, out_format, pre_multiply, idx, out_pixels ); + + PEP_FREE( idx ); + return out_pixels; +} + +void pep_free( pep* in_pep ) +{ + if( in_pep && in_pep->bytes ) + { + free( in_pep->bytes ); + in_pep->bytes = NULL; + in_pep->bytes_size = 0; + } +} + +#pragma endregion visible + +#pragma endregion compression + +//////////////////////////////////////////////////////////////// +#pragma region - serialization + +uint8_t* pep_serialize( const pep* in_pep, uint32_t* const out_size ) +{ + if( !in_pep || !in_pep->width || !in_pep->height || !in_pep->bytes_size || !in_pep->bytes ) + { + *out_size = 0; + return NULL; + } + + uint16_t palette_count = in_pep->palette_size ? in_pep->palette_size : 256; + + const uint16_t w = in_pep->width - 1; + const uint16_t h = in_pep->height - 1; + const uint8_t is_small = ( w <= 255 && h <= 255 ) ? 1 : 0; + const uint8_t dim_bytes = is_small ? 2 : 3; + + // calculate variable-length size bytes + uint8_t size_bytes = 0; + uint32_t temp_size = in_pep->bytes_size; + while( temp_size >= 0x80 ) + { + size_bytes++; + temp_size >>= 7; + } + ++size_bytes; + + // check if bitmap (black and white) + uint8_t is_bitmap = 0; + if( palette_count == 2 ) + { + const uint8_t* const color0 = ( uint8_t* )( &in_pep->palette[ 0 ] ); + const uint8_t* const color1 = ( uint8_t* )( &in_pep->palette[ 1 ] ); + + const uint8_t is_white0 = ( color0[ 0 ] == 255 && color0[ 1 ] == 255 && color0[ 2 ] == 255 && color0[ 3 ] == 255 ); + const uint8_t is_white1 = ( color1[ 0 ] == 255 && color1[ 1 ] == 255 && color1[ 2 ] == 255 && color1[ 3 ] == 255 ); + + if( in_pep->format <= pep_bgra ) + { + is_bitmap = ( ( is_white0 && color1[ 0 ] == 0 && color1[ 1 ] == 0 && color1[ 2 ] == 0 && color1[ 3 ] == 255 ) || ( color0[ 0 ] == 0 && color0[ 1 ] == 0 && color0[ 2 ] == 0 && color0[ 3 ] == 255 && is_white1 ) ); + } + else + { + is_bitmap = ( ( is_white0 && color1[ 0 ] == 255 && color1[ 1 ] == 0 && color1[ 2 ] == 0 && color1[ 3 ] == 0 ) || ( color0[ 0 ] == 255 && color0[ 1 ] == 0 && color0[ 2 ] == 0 && color0[ 3 ] == 0 && is_white1 ) ); + } + } + + // check if all palette alphas are 255 + uint8_t only_rgb = 1; + if( !is_bitmap ) + { + for( uint16_t index = 0; index < palette_count; index++ ) + { + if( ( ( ( uint8_t* )( &in_pep->palette[ index ] ) )[ 3 ] ) != 0xff ) + { + only_rgb = 0; + break; + } + } + } + + // calculate palette bytes + uint16_t palette_bytes = 0; + if( !is_bitmap ) + { + const uint16_t channel_bits = 1 << in_pep->channel_bits; + if( channel_bits == 8 ) + { + palette_bytes = palette_count * ( only_rgb ? 3 : 4 ); + } + else + { + const uint16_t channels = only_rgb ? 3 : 4; + palette_bytes = ( channel_bits * channels * palette_count + 7 ) >> 3; + } + } + + // allocate the exact size (subtract 1 for palette_size byte if bitmap) + const uint64_t total_size = dim_bytes + size_bytes + ( is_bitmap ? 0 : 1 ) + palette_bytes + in_pep->bytes_size + 4 + 1; + uint8_t* out_bytes = ( uint8_t* )PEP_MALLOC( total_size ); + uint8_t* out_bytes_ref = out_bytes; + + // flags: format (2), channel_bits (2), is_small (1), only_rgb (1), is_bitmap (1) + *out_bytes_ref++= ( in_pep->format & 0x3 ) | ( ( in_pep->channel_bits & 0x3 ) << 2 ) | ( ( is_small & 0x1 ) << 4 ) | ( ( only_rgb & 0x1 ) << 5 ) | ( ( is_bitmap & 0x1 ) << 6 ); + *out_bytes_ref++= in_pep->model; // takes the last extra byte + + // width/height + if( is_small ) + { + *out_bytes_ref++= w & 0xff; + *out_bytes_ref++= h & 0xff; + } + else + { + const uint32_t packed_dims = ( ( w & 0xfff ) << 12 ) | ( h & 0xfff ); + *out_bytes_ref++= ( packed_dims >> 16 ) & 0xff; + *out_bytes_ref++= ( packed_dims >> 8 ) & 0xff; + *out_bytes_ref++= packed_dims & 0xff; + } + + // variable-length size + uint32_t size = in_pep->bytes_size; + while( size >= 0x80 ) + { + *out_bytes_ref++= ( size | 0x80 ) & 0xff; + size >>= 7; + } + *out_bytes_ref++= size; + + if( !is_bitmap ) + { + // palette size + *out_bytes_ref++= in_pep->palette_size; + + // palette + const uint16_t channel_bits = 1 << in_pep->channel_bits; + const uint8_t shift = 8 - channel_bits; + const uint8_t mask = ( 1 << channel_bits ) - 1; + + if( channel_bits == 8 ) + { + for( uint16_t index = 0; index < palette_count; index++ ) + { + uint8_t* color = ( uint8_t* )( &( in_pep->palette[ index ] ) ); + *out_bytes_ref++= color[ 0 ]; + *out_bytes_ref++= color[ 1 ]; + *out_bytes_ref++= color[ 2 ]; + if( !only_rgb ) *out_bytes_ref++= color[ 3 ]; + } + } + else + { + uint32_t bit_buffer = 0; + uint8_t bit_count = 0; + + for( uint16_t index = 0; index < palette_count; index++ ) + { + uint8_t* color = ( uint8_t* )( &( in_pep->palette[ index ] ) ); + + bit_buffer = ( bit_buffer << channel_bits ) | ( ( color[ 0 ] >> shift ) &mask ); + bit_buffer = ( bit_buffer << channel_bits ) | ( ( color[ 1 ] >> shift ) &mask ); + bit_buffer = ( bit_buffer << channel_bits ) | ( ( color[ 2 ] >> shift ) &mask ); + bit_count += channel_bits * 3; + + if( !only_rgb ) + { + bit_buffer = ( bit_buffer << channel_bits ) | ( ( color[ 3 ] >> shift ) &mask ); + bit_count += channel_bits; + } + + while( bit_count >= 8 ) + { + bit_count -= 8; + *out_bytes_ref++= ( bit_buffer >> bit_count ) & 0xff; + } + } + + if( bit_count > 0 ) + { + *out_bytes_ref++= ( bit_buffer << ( 8 - bit_count ) ) & 0xff; + } + } + } + + memcpy( out_bytes_ref, in_pep->bytes, in_pep->bytes_size ); + out_bytes_ref += in_pep->bytes_size; + *out_bytes_ref = '\0'; + + *out_size = out_bytes_ref - out_bytes; + return out_bytes; +} + +pep pep_deserialize( const uint8_t* const in_bytes, const uint32_t in_bytes_size ) +{ + pep out_pep = { 0 }; + + if( !in_bytes || in_bytes_size == 0 ) return out_pep; + + const uint8_t* bytes_ref = in_bytes; + const uint8_t* const bytes_end = in_bytes + in_bytes_size; + + // packed flags + if( bytes_ref + 1 > bytes_end ) return out_pep; + uint8_t packed_flags = *bytes_ref++; + if( bytes_ref + 1 > bytes_end ) return out_pep; + out_pep.model = *bytes_ref++; + out_pep.format = ( pep_format ) ( packed_flags & 0x3 ); + out_pep.channel_bits = ( pep_channel_bits ) ( ( packed_flags >> 2 ) & 0x3 ); + uint8_t is_small = ( packed_flags >> 4 ) & 0x1; + uint8_t only_rgb = ( packed_flags >> 5 ) & 0x1; + uint8_t is_bitmap = ( packed_flags >> 6 ) & 0x1; + + // width/height + uint8_t dim_bytes = is_small ? 2 : 3; + if( bytes_ref + dim_bytes > bytes_end ) return out_pep; + uint16_t w, + h; + if( is_small ) + { + w = *bytes_ref++; + h = *bytes_ref++; + } + else + { + uint32_t packed_dims = ( *bytes_ref++ << 16 ); + packed_dims |= ( *bytes_ref++ << 8 ); + packed_dims |= *bytes_ref++; + w = ( packed_dims >> 12 ) & 0xfff; + h = packed_dims & 0xfff; + } + out_pep.width = w + 1; + out_pep.height = h + 1; + + // variable-length size + uint32_t bytes_size = 0; + uint8_t shift = 0; + uint8_t byte_val; + do + { + if( bytes_ref >= bytes_end ) return out_pep; + byte_val = *bytes_ref++; + if( shift < 32 ) bytes_size |= ( ( uint32_t )( byte_val &0x7f ) ) << shift; + shift += 7; + } + while( ( byte_val & 0x80 ) && shift < 35 ); + out_pep.bytes_size = bytes_size; + + // handle bitmap or read palette + uint32_t remaining = ( uint32_t )( bytes_end - bytes_ref ); + + if( is_bitmap ) + { + if( remaining < bytes_size ) return out_pep; + + out_pep.palette_size = 2; + out_pep.palette[ 0 ] = out_pep.format <= pep_bgra ? 0xff000000 : 0x000000ff; + out_pep.palette[ 1 ] = 0xffffffff; + } + else + { + // palette size + if( remaining < 1 ) return out_pep; + out_pep.palette_size = *bytes_ref++; + remaining--; + + uint16_t palette_count = out_pep.palette_size ? out_pep.palette_size : 256; + + // palette + const uint8_t channel_bits = 1 << out_pep.channel_bits; + const uint8_t mask = ( 1 << channel_bits ) - 1; + uint32_t palette_bytes; + if( channel_bits == 8 ) + { + palette_bytes = palette_count * ( only_rgb ? 3 : 4 ); + } + else + { + uint16_t channels = only_rgb ? 3 : 4; + palette_bytes = ( channel_bits * channels * palette_count + 7 ) >> 3; + } + + if( remaining < palette_bytes || remaining - palette_bytes < bytes_size ) return out_pep; + + if( channel_bits == 8 ) + { + for( uint16_t index = 0; index < palette_count; index++ ) + { + uint8_t* color = ( uint8_t* )( &( out_pep.palette[ index ] ) ); + color[ 0 ] = *bytes_ref++; + color[ 1 ] = *bytes_ref++; + color[ 2 ] = *bytes_ref++; + color[ 3 ] = only_rgb ? 0xff : *bytes_ref++; + } + } + else + { + uint32_t bit_buffer = 0; + uint8_t bit_count = 0; + + for( uint16_t index = 0; index < palette_count; index++ ) + { + uint8_t channels = only_rgb ? 3 : 4; + uint8_t channel_values[ 4 ]; + + for( uint8_t c = 0; c < channels; c++ ) + { + while( bit_count < channel_bits ) + { + bit_buffer = ( bit_buffer << 8 ) | *bytes_ref++; + bit_count += 8; + } + bit_count -= channel_bits; + channel_values[ c ] = ( bit_buffer >> bit_count ) & mask; + + uint8_t scaled = channel_values[ c ] << ( 8 - channel_bits ); + if( channel_bits < 8 ) + { + scaled |= ( scaled >> channel_bits ); + if( channel_bits < 4 ) + { + scaled |= ( scaled >> ( 2 * channel_bits ) ); + } + } + channel_values[ c ] = scaled; + } + + uint8_t* color = ( uint8_t* )( &( out_pep.palette[ index ] ) ); + color[ 0 ] = channel_values[ 0 ]; + color[ 1 ] = channel_values[ 1 ]; + color[ 2 ] = channel_values[ 2 ]; + color[ 3 ] = only_rgb ? 0xff : channel_values[ 3 ]; + } + } + } + + // copy image data + out_pep.bytes = ( uint8_t* )PEP_MALLOC( bytes_size ); + if( out_pep.bytes ) + { + memcpy( out_pep.bytes, bytes_ref, bytes_size ); + } + + return out_pep; +} + +#pragma endregion serialization + +//////////////////////////////////////////////////////////////// +#pragma region - file + +// For both save/load, file_path should end in ".pep": +// e.g. "texture.pep", "assets/image.pep" + +// Saves pep into a file. +// Returns 0 on failure, 1 on success +uint8_t pep_save( const pep* const in_pep, const char* const file_path ) +{ + if( !in_pep || !file_path ) + { + return 0; + } + + uint32_t bytes_size = 0; + uint8_t* bytes = pep_serialize( in_pep, &bytes_size ); + + if( !bytes || bytes_size == 0 ) + { + return 0; + } + + FILE * file = fopen( file_path, "wb" ); + if( !file ) + { + PEP_FREE( bytes ); + return 0; + } + + size_t written = fwrite( bytes, 1, bytes_size, file ); + + fclose( file ); + PEP_FREE( bytes ); + + #ifdef PEP_DEBUG + printf( "pep: %lld\nfile: %zu\nmodel: %d\n", in_pep->bytes_size, written, in_pep->model ); + #endif + + return written == bytes_size; +} + +// Loads .pep file into returned pep struct +pep pep_load( const char* const file_path ) +{ + pep out_pep = { 0 }; + + if( !file_path ) + { + return out_pep; + } + + FILE * file = fopen( file_path, "rb" ); + if( !file ) + { + return out_pep; + } + + fseek( file, 0, SEEK_END ); + long file_size = ftell( file ); + fseek( file, 0, SEEK_SET ); + + if( file_size <= 0 ) + { + fclose( file ); + return out_pep; + } + + uint8_t* bytes = ( uint8_t* )PEP_MALLOC( file_size ); + + size_t read = fread( bytes, 1, file_size, file ); + fclose( file ); + + if( read != ( size_t ) file_size ) + { + PEP_FREE( bytes ); + return out_pep; + } + + out_pep = pep_deserialize( bytes, ( uint32_t )read ); + PEP_FREE( bytes ); + + #ifdef PEP_DEBUG + printf( "\npep: %lld\nfile: %ld\n", out_pep.bytes_size, file_size ); + #endif + + return out_pep; +} + +#pragma endregion file + +#ifdef _MSC_VER + #pragma warning( pop ) +#endif + +#endif // PEP_IMPLEMENTATION + + +#pragma endregion definitions + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/rtextures.c b/src/rtextures.c index 724fe73cd..35edd2098 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -12,6 +12,7 @@ * #define SUPPORT_FILEFORMAT_JPG 0 * #define SUPPORT_FILEFORMAT_GIF 1 * #define SUPPORT_FILEFORMAT_QOI 1 +* #define SUPPORT_FILEFORMAT_PEP 1 * #define SUPPORT_FILEFORMAT_PSD 0 * #define SUPPORT_FILEFORMAT_HDR 0 * #define SUPPORT_FILEFORMAT_PIC 0 @@ -188,7 +189,15 @@ #if defined(_MSC_VER) #pragma warning(pop) // Disable MSVC warning suppression #endif +#endif +#if SUPPORT_FILEFORMAT_PEP + #define PEP_MALLOC RL_MALLOC + #define PEP_REALLOC RL_REALLOC + #define PEP_FREE RL_FREE + + #define PEP_IMPLEMENTATION + #include "external/pep.h" #endif #if SUPPORT_IMAGE_EXPORT @@ -510,6 +519,31 @@ Image LoadImageFromMemory(const char *fileType, const unsigned char *fileData, i } } #endif +#if SUPPORT_FILEFORMAT_PEP + else if ((strcmp(fileType, ".pep") == 0) || (strcmp(fileType, ".PEP") == 0)) + { + if (fileData != NULL) + { + // Deserialize file data into pep structure + pep p = pep_deserialize(fileData, dataSize); + + // Decompress pep data for image struct + // Decompression options: + // - First color transparent, 3rd parameter: 1 + // - Premultiply alpha on loading, 4th parameter: 1 + unsigned int *pepData = pep_decompress(&p, pep_rgba, 1, 1); + + image.data = pepData; + image.width = p.width; + image.height = p.height; + image.format = PIXELFORMAT_UNCOMPRESSED_R8G8B8A8; + image.mipmaps = 1; + + PEP_FREE(pepData); + pep_free(&p); + } + } +#endif #if SUPPORT_FILEFORMAT_DDS else if ((strcmp(fileType, ".dds") == 0) || (strcmp(fileType, ".DDS") == 0)) { @@ -681,6 +715,25 @@ bool ExportImage(Image image, const char *fileName) } } #endif +#if SUPPORT_FILEFORMAT_PEP + else if (IsFileExtension(fileName, ".pep")) + { + if (image.format == PIXELFORMAT_UNCOMPRESSED_R8G8B8A8) + { + // NOTE: Only RGBA 32bit (8bit per channel) image format supported + pep p = pep_compress(image.data, image.width, image.height, pep_rgba, pep_8bit); + + unsigned int pepDataSize = 0; + unsigned char *pepData = pep_serialize(&p, &pepDataSize); + + result = SaveFileData(fileName, pepData, pepDataSize); + + PEP_FREE(pepData); + pep_free(&p); + } + else TRACELOG(LOG_WARNING, "IMAGE: Image can not be exported, .pep requires RGBA 32bit input"); + } +#endif #if SUPPORT_FILEFORMAT_KTX else if (IsFileExtension(fileName, ".ktx")) { From 2c24ca1407c60f0fee92fa1458d4033c7860d943 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 1 Jul 2026 11:55:43 +0200 Subject: [PATCH 20/94] Typos --- src/platforms/rcore_desktop_sdl.c | 2 +- src/platforms/rcore_desktop_win32.c | 2 +- src/rlgl.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 8ff17271f..c96820475 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -863,7 +863,7 @@ void SetWindowMonitor(int monitor) // ending up positioned partly outside the target display // NOTE 2: The workaround for that is, previously to moving the window, // setting the window size to the target display size, so they match - // NOTE 3: It wasn't done here because it can not bee assumed that changing + // NOTE 3: It wasn't done here because it can not be assumed that changing // the window size automatically is acceptable behavior by the user SDL_SetWindowPosition(platform.window, usableBounds.x, usableBounds.y); CORE.Window.position.x = usableBounds.x; diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c index ef40caa9e..35347023d 100644 --- a/src/platforms/rcore_desktop_win32.c +++ b/src/platforms/rcore_desktop_win32.c @@ -2213,7 +2213,7 @@ static unsigned SanitizeFlags(int mode, unsigned flags) // // This design takes care of many odd corner cases. For example, in case of restoring // a window that was previously maximized AND minimized and those two flags need to be removed, -// ShowWindow with SW_RESTORE twice need to bee actually calleed. Another example is +// ShowWindow with SW_RESTORE twice need to be actually calleed. Another example is // wheen having a maximized window, if the undecorated flag is modified then the window style // needs to be updated, but updating the style would mean the window size would change // causing the window to lose its Maximized state which would mean the window size diff --git a/src/rlgl.h b/src/rlgl.h index 5e34f7bde..d72469e11 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -2989,7 +2989,7 @@ void rlDrawRenderBatch(rlRenderBatch *batch) // NOTE: glMapBuffer() causes sync issue // If GPU is working with this buffer, glMapBuffer() will wait(stall) until GPU to finish its job - // To avoid waiting (idle), glBufferData() can bee called first with NULL pointer before glMapBuffer() + // To avoid waiting (idle), glBufferData() can be called first with NULL pointer before glMapBuffer() // Doing that, the previous data in PBO will be discarded and glMapBuffer() returns a new // allocated pointer immediately even if GPU is still working with the previous data From 122e378e93bf3c71827c28966bcd432e4e2e10a0 Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 1 Jul 2026 12:09:26 +0200 Subject: [PATCH 21/94] ADDED: New image drawing functions, aligned with texture/text drawing -WIP- The new functions are direct maps of the Texture2D equivalents, they can be useful for a future mapping Texture2D --> Image; an alternative 2d software renderer... --- src/raylib.h | 4 ++++ src/rtextures.c | 29 ++++++++++++++++++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index e49d6b2f7..445b0a875 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1431,8 +1431,10 @@ RLAPI void ImageDrawTriangleStrip(Image *dst, const Vector2 *points, int pointCo RLAPI void ImageDrawRectangle(Image *dst, int posX, int posY, int width, int height, Color color); // Draw rectangle within an image RLAPI void ImageDrawRectangleV(Image *dst, Vector2 position, Vector2 size, Color color); // Draw rectangle within an image (Vector version) RLAPI void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color); // Draw rectangle within an image +RLAPI void ImageDrawRectanglePro(Image *dst, Rectangle rec, Vector2 origin, float rotation, Color color); // Draw a color-filled rectangle with pro parameters within and image RLAPI void ImageDrawRectangleLines(Image *dst, int posX, int posY, int width, int height, Color color); // Draw rectangle lines within an image RLAPI void ImageDrawRectangleLinesEx(Image *dst, Rectangle rec, int thick, Color color); // Draw rectangle lines within an image with line thickness +RLAPI void ImageDrawRectangleGradientEx(Image *dst, Rectangle rec, Color col1, Color col2, Color col3, Color col4); // Draw rectangle with gradient colors within an image, counter-clockwise color order RLAPI void ImageDrawCircle(Image *dst, int centerX, int centerY, int radius, Color color); // Draw a filled circle within an image RLAPI void ImageDrawCircleV(Image *dst, Vector2 center, int radius, Color color); // Draw a filled circle within an image (Vector version) RLAPI void ImageDrawCircleLines(Image *dst, int centerX, int centerY, int radius, Color color); // Draw circle outline within an image @@ -1440,10 +1442,12 @@ RLAPI void ImageDrawCircleLinesV(Image *dst, Vector2 center, int radius, Color c RLAPI void ImageDrawCircleGradient(Image *dst, Vector2 center, float radius, Color inner, Color outer); // Draw a gradient-filled circle within an image RLAPI void ImageDrawImage(Image *dst, Image src, int posX, int posY, Color tint); // Draw an image within an image +RLAPI void ImageDrawImageEx(Image *dst, Image src, Vector2 position, float rotation, float scale, Color tint); // Draw an image with scaling and rotation within an image RLAPI void ImageDrawImageRec(Image *dst, Image src, Rectangle srcRec, Vector2 position, Color tint); // Draw a part of an image defined by a rectangle within an image RLAPI void ImageDrawImagePro(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Vector2 origin, float rotation, Color tint); // Draw a part of an image defined by a rectangle into destination rectangle, with scaling and rotation, within an image RLAPI void ImageDrawText(Image *dst, const char *text, int posX, int posY, int fontSize, Color color); // Draw text (using default font) within an image (destination) RLAPI void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, float fontSize, float spacing, Color tint); // Draw text (custom sprite font) within an image (destination) +RLAPI void ImageDrawTextPro(Image *dst, Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint); // Draw text using Font and pro parameters (rotation) // Texture loading functions // NOTE: These functions require GPU access diff --git a/src/rtextures.c b/src/rtextures.c index 35edd2098..ce79c5627 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -3918,6 +3918,12 @@ void ImageDrawRectangleRec(Image *dst, Rectangle rec, Color color) } } +// Draw a color-filled rectangle with pro parameters within and image +void ImageDrawRectanglePro(Image *dst, Rectangle rec, Vector2 origin, float rotation, Color color) +{ + // TODO: NEW: Implement ImageDrawRectanglePro() +} + // Draw rectangle lines within an image void ImageDrawRectangleLines(Image *dst, int posX, int posY, int width, int height, Color color) { @@ -3934,6 +3940,12 @@ void ImageDrawRectangleLinesEx(Image *dst, Rectangle rec, int thick, Color color ImageDrawRectangle(dst, (int)rec.x, (int)(rec.y + rec.height - thick), (int)rec.width, thick, color); } +// Draw rectangle with gradient colors within an image, counter-clockwise color order +void ImageDrawRectangleGradientEx(Image *dst, Rectangle rec, Color col1, Color col2, Color col3, Color col4) +{ + // TODO: NEW: Implement ImageDrawRectangleGradientEx() +} + // Draw circle within an image void ImageDrawCircle(Image *dst, int centerX, int centerY, int radius, Color color) { @@ -4001,7 +4013,7 @@ void ImageDrawCircleLinesV(Image *dst, Vector2 center, int radius, Color color) // Draw a gradient-filled circle within an image void ImageDrawCircleGradient(Image *dst, Vector2 center, float radius, Color inner, Color outer) { - // TODO: Implement gradient circle drawing + // TODO: NEW: Implement ImageDrawCircleGradient() } // Draw an image within an image @@ -4012,6 +4024,12 @@ void ImageDrawImage(Image *dst, Image src, int posX, int posY, Color tint) ImageDrawImagePro(dst, src, srcRec, dstRec, (Vector2){ 0 }, 0.0f, tint); } +// Draw an image with scaling and rotation within an image +void ImageDrawImageEx(Image *dst, Image src, Vector2 position, float rotation, float scale, Color tint) +{ + // TODO: NEW: Implement ImageDrawImageEx() +} + // Draw a part of an image defined by a rectangle within an image void ImageDrawImageRec(Image *dst, Image src, Rectangle srcRec, Vector2 position, Color tint) { @@ -4020,8 +4038,7 @@ void ImageDrawImageRec(Image *dst, Image src, Rectangle srcRec, Vector2 position } // Draw a part of an image defined by a rectangle into destination rectangle, with scaling and rotation, within an image -// NOTE: Color tint is applied to source image -// TODO: WARNING: origin and rotation are not implemented +// TODO: REVIEW: ImageDrawImagePro(), implement origin and rotation for image drawing void ImageDrawImagePro(Image *dst, Image src, Rectangle srcRec, Rectangle dstRec, Vector2 origin, float rotation, Color tint) { // Security check to avoid program crash @@ -4199,6 +4216,12 @@ void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, UnloadImage(imText); } +// Draw text using Font and pro parameters (rotation) +void ImageDrawTextPro(Image *dst, Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint) +{ + // TODO: NEW: Implement ImageDrawImageEx() +} + //------------------------------------------------------------------------------------ // Texture loading functions //------------------------------------------------------------------------------------ From 9deaae0716e58385dcb6428218a11ca75a83e5ac Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 1 Jul 2026 10:09:45 +0000 Subject: [PATCH 22/94] rlparser: update raylib_api.* by CI --- tools/rlparser/output/raylib_api.json | 132 + tools/rlparser/output/raylib_api.lua | 54 + tools/rlparser/output/raylib_api.sexpr | 6582 ++++++++++++++++++++++++ tools/rlparser/output/raylib_api.txt | 536 +- tools/rlparser/output/raylib_api.xml | 36 +- 5 files changed, 7092 insertions(+), 248 deletions(-) create mode 100644 tools/rlparser/output/raylib_api.sexpr diff --git a/tools/rlparser/output/raylib_api.json b/tools/rlparser/output/raylib_api.json index f26dac263..ffac7e6da 100644 --- a/tools/rlparser/output/raylib_api.json +++ b/tools/rlparser/output/raylib_api.json @@ -8455,6 +8455,33 @@ } ] }, + { + "name": "ImageDrawRectanglePro", + "description": "Draw a color-filled rectangle with pro parameters within and image", + "returnType": "void", + "params": [ + { + "type": "Image *", + "name": "dst" + }, + { + "type": "Rectangle", + "name": "rec" + }, + { + "type": "Vector2", + "name": "origin" + }, + { + "type": "float", + "name": "rotation" + }, + { + "type": "Color", + "name": "color" + } + ] + }, { "name": "ImageDrawRectangleLines", "description": "Draw rectangle lines within an image", @@ -8509,6 +8536,37 @@ } ] }, + { + "name": "ImageDrawRectangleGradientEx", + "description": "Draw rectangle with gradient colors within an image, counter-clockwise color order", + "returnType": "void", + "params": [ + { + "type": "Image *", + "name": "dst" + }, + { + "type": "Rectangle", + "name": "rec" + }, + { + "type": "Color", + "name": "col1" + }, + { + "type": "Color", + "name": "col2" + }, + { + "type": "Color", + "name": "col3" + }, + { + "type": "Color", + "name": "col4" + } + ] + }, { "name": "ImageDrawCircle", "description": "Draw a filled circle within an image", @@ -8663,6 +8721,37 @@ } ] }, + { + "name": "ImageDrawImageEx", + "description": "Draw an image with scaling and rotation within an image", + "returnType": "void", + "params": [ + { + "type": "Image *", + "name": "dst" + }, + { + "type": "Image", + "name": "src" + }, + { + "type": "Vector2", + "name": "position" + }, + { + "type": "float", + "name": "rotation" + }, + { + "type": "float", + "name": "scale" + }, + { + "type": "Color", + "name": "tint" + } + ] + }, { "name": "ImageDrawImageRec", "description": "Draw a part of an image defined by a rectangle within an image", @@ -8791,6 +8880,49 @@ } ] }, + { + "name": "ImageDrawTextPro", + "description": "Draw text using Font and pro parameters (rotation)", + "returnType": "void", + "params": [ + { + "type": "Image *", + "name": "dst" + }, + { + "type": "Font", + "name": "font" + }, + { + "type": "const char *", + "name": "text" + }, + { + "type": "Vector2", + "name": "position" + }, + { + "type": "Vector2", + "name": "origin" + }, + { + "type": "float", + "name": "rotation" + }, + { + "type": "float", + "name": "fontSize" + }, + { + "type": "float", + "name": "spacing" + }, + { + "type": "Color", + "name": "tint" + } + ] + }, { "name": "LoadTexture", "description": "Load texture from file into GPU memory (VRAM)", diff --git a/tools/rlparser/output/raylib_api.lua b/tools/rlparser/output/raylib_api.lua index 8c26fcac6..945e864ac 100644 --- a/tools/rlparser/output/raylib_api.lua +++ b/tools/rlparser/output/raylib_api.lua @@ -6232,6 +6232,18 @@ return { {type = "Color", name = "color"} } }, + { + name = "ImageDrawRectanglePro", + description = "Draw a color-filled rectangle with pro parameters within and image", + returnType = "void", + params = { + {type = "Image *", name = "dst"}, + {type = "Rectangle", name = "rec"}, + {type = "Vector2", name = "origin"}, + {type = "float", name = "rotation"}, + {type = "Color", name = "color"} + } + }, { name = "ImageDrawRectangleLines", description = "Draw rectangle lines within an image", @@ -6256,6 +6268,19 @@ return { {type = "Color", name = "color"} } }, + { + name = "ImageDrawRectangleGradientEx", + description = "Draw rectangle with gradient colors within an image, counter-clockwise color order", + returnType = "void", + params = { + {type = "Image *", name = "dst"}, + {type = "Rectangle", name = "rec"}, + {type = "Color", name = "col1"}, + {type = "Color", name = "col2"}, + {type = "Color", name = "col3"}, + {type = "Color", name = "col4"} + } + }, { name = "ImageDrawCircle", description = "Draw a filled circle within an image", @@ -6326,6 +6351,19 @@ return { {type = "Color", name = "tint"} } }, + { + name = "ImageDrawImageEx", + description = "Draw an image with scaling and rotation within an image", + returnType = "void", + params = { + {type = "Image *", name = "dst"}, + {type = "Image", name = "src"}, + {type = "Vector2", name = "position"}, + {type = "float", name = "rotation"}, + {type = "float", name = "scale"}, + {type = "Color", name = "tint"} + } + }, { name = "ImageDrawImageRec", description = "Draw a part of an image defined by a rectangle within an image", @@ -6379,6 +6417,22 @@ return { {type = "Color", name = "tint"} } }, + { + name = "ImageDrawTextPro", + description = "Draw text using Font and pro parameters (rotation)", + returnType = "void", + params = { + {type = "Image *", name = "dst"}, + {type = "Font", name = "font"}, + {type = "const char *", name = "text"}, + {type = "Vector2", name = "position"}, + {type = "Vector2", name = "origin"}, + {type = "float", name = "rotation"}, + {type = "float", name = "fontSize"}, + {type = "float", name = "spacing"}, + {type = "Color", name = "tint"} + } + }, { name = "LoadTexture", description = "Load texture from file into GPU memory (VRAM)", diff --git a/tools/rlparser/output/raylib_api.sexpr b/tools/rlparser/output/raylib_api.sexpr new file mode 100644 index 000000000..bb35bea10 --- /dev/null +++ b/tools/rlparser/output/raylib_api.sexpr @@ -0,0 +1,6582 @@ +((defines + ((name "RAYLIB_H") + (type "GUARD") + (value "") + (description "")) + ((name "RAYLIB_VERSION_MAJOR") + (type "INT") + (value 6) + (description "")) + ((name "RAYLIB_VERSION_MINOR") + (type "INT") + (value 1) + (description "")) + ((name "RAYLIB_VERSION_PATCH") + (type "INT") + (value 0) + (description "")) + ((name "RAYLIB_VERSION") + (type "STRING") + (value "6.1-dev") + (description "")) + ((name "__declspec(x)") + (type "MACRO") + (value "__attribute__((x))") + (description "")) + ((name "RLAPI") + (type "UNKNOWN") + (value "__declspec(dllexport)") + (description "Building the library as a Win32 shared library (.dll)")) + ((name "PI") + (type "FLOAT") + (value 3.14159265358979323846) + (description "")) + ((name "DEG2RAD") + (type "FLOAT_MATH") + (value "(PI/180.0f)") + (description "")) + ((name "RAD2DEG") + (type "FLOAT_MATH") + (value "(180.0f/PI)") + (description "")) + ((name "RL_MALLOC(sz)") + (type "MACRO") + (value "malloc(sz)") + (description "")) + ((name "RL_CALLOC(n,sz)") + (type "MACRO") + (value "calloc(n,sz)") + (description "")) + ((name "RL_REALLOC(ptr,sz)") + (type "MACRO") + (value "realloc(ptr,sz)") + (description "")) + ((name "RL_FREE(ptr)") + (type "MACRO") + (value "free(ptr)") + (description "")) + ((name "CLITERAL(type)") + (type "MACRO") + (value "type") + (description "")) + ((name "RL_COLOR_TYPE") + (type "GUARD") + (value "") + (description "")) + ((name "RL_RECTANGLE_TYPE") + (type "GUARD") + (value "") + (description "")) + ((name "RL_VECTOR2_TYPE") + (type "GUARD") + (value "") + (description "")) + ((name "RL_VECTOR3_TYPE") + (type "GUARD") + (value "") + (description "")) + ((name "RL_VECTOR4_TYPE") + (type "GUARD") + (value "") + (description "")) + ((name "RL_QUATERNION_TYPE") + (type "GUARD") + (value "") + (description "")) + ((name "RL_MATRIX_TYPE") + (type "GUARD") + (value "") + (description "")) + ((name "LIGHTGRAY") + (type "COLOR") + (value "CLITERAL(Color){ 200, 200, 200, 255 }") + (description "Light Gray")) + ((name "GRAY") + (type "COLOR") + (value "CLITERAL(Color){ 130, 130, 130, 255 }") + (description "Gray")) + ((name "DARKGRAY") + (type "COLOR") + (value "CLITERAL(Color){ 80, 80, 80, 255 }") + (description "Dark Gray")) + ((name "YELLOW") + (type "COLOR") + (value "CLITERAL(Color){ 253, 249, 0, 255 }") + (description "Yellow")) + ((name "GOLD") + (type "COLOR") + (value "CLITERAL(Color){ 255, 203, 0, 255 }") + (description "Gold")) + ((name "ORANGE") + (type "COLOR") + (value "CLITERAL(Color){ 255, 161, 0, 255 }") + (description "Orange")) + ((name "PINK") + (type "COLOR") + (value "CLITERAL(Color){ 255, 109, 194, 255 }") + (description "Pink")) + ((name "RED") + (type "COLOR") + (value "CLITERAL(Color){ 230, 41, 55, 255 }") + (description "Red")) + ((name "MAROON") + (type "COLOR") + (value "CLITERAL(Color){ 190, 33, 55, 255 }") + (description "Maroon")) + ((name "GREEN") + (type "COLOR") + (value "CLITERAL(Color){ 0, 228, 48, 255 }") + (description "Green")) + ((name "LIME") + (type "COLOR") + (value "CLITERAL(Color){ 0, 158, 47, 255 }") + (description "Lime")) + ((name "DARKGREEN") + (type "COLOR") + (value "CLITERAL(Color){ 0, 117, 44, 255 }") + (description "Dark Green")) + ((name "SKYBLUE") + (type "COLOR") + (value "CLITERAL(Color){ 102, 191, 255, 255 }") + (description "Sky Blue")) + ((name "BLUE") + (type "COLOR") + (value "CLITERAL(Color){ 0, 121, 241, 255 }") + (description "Blue")) + ((name "DARKBLUE") + (type "COLOR") + (value "CLITERAL(Color){ 0, 82, 172, 255 }") + (description "Dark Blue")) + ((name "PURPLE") + (type "COLOR") + (value "CLITERAL(Color){ 200, 122, 255, 255 }") + (description "Purple")) + ((name "VIOLET") + (type "COLOR") + (value "CLITERAL(Color){ 135, 60, 190, 255 }") + (description "Violet")) + ((name "DARKPURPLE") + (type "COLOR") + (value "CLITERAL(Color){ 112, 31, 126, 255 }") + (description "Dark Purple")) + ((name "BEIGE") + (type "COLOR") + (value "CLITERAL(Color){ 211, 176, 131, 255 }") + (description "Beige")) + ((name "BROWN") + (type "COLOR") + (value "CLITERAL(Color){ 127, 106, 79, 255 }") + (description "Brown")) + ((name "DARKBROWN") + (type "COLOR") + (value "CLITERAL(Color){ 76, 63, 47, 255 }") + (description "Dark Brown")) + ((name "WHITE") + (type "COLOR") + (value "CLITERAL(Color){ 255, 255, 255, 255 }") + (description "White")) + ((name "BLACK") + (type "COLOR") + (value "CLITERAL(Color){ 0, 0, 0, 255 }") + (description "Black")) + ((name "BLANK") + (type "COLOR") + (value "CLITERAL(Color){ 0, 0, 0, 0 }") + (description "Blank (Transparent)")) + ((name "MAGENTA") + (type "COLOR") + (value "CLITERAL(Color){ 255, 0, 255, 255 }") + (description "Magenta")) + ((name "RAYWHITE") + (type "COLOR") + (value "CLITERAL(Color){ 245, 245, 245, 255 }") + (description "My own White (raylib logo)")) + ((name "RL_BOOL_TYPE") + (type "GUARD") + (value "") + (description "")) + ((name "MOUSE_LEFT_BUTTON") + (type "UNKNOWN") + (value "MOUSE_BUTTON_LEFT") + (description "")) + ((name "MOUSE_RIGHT_BUTTON") + (type "UNKNOWN") + (value "MOUSE_BUTTON_RIGHT") + (description "")) + ((name "MOUSE_MIDDLE_BUTTON") + (type "UNKNOWN") + (value "MOUSE_BUTTON_MIDDLE") + (description "")) + ((name "MATERIAL_MAP_DIFFUSE") + (type "UNKNOWN") + (value "MATERIAL_MAP_ALBEDO") + (description "")) + ((name "MATERIAL_MAP_SPECULAR") + (type "UNKNOWN") + (value "MATERIAL_MAP_METALNESS") + (description "")) + ((name "SHADER_LOC_MAP_DIFFUSE") + (type "UNKNOWN") + (value "SHADER_LOC_MAP_ALBEDO") + (description "")) + ((name "SHADER_LOC_MAP_SPECULAR") + (type "UNKNOWN") + (value "SHADER_LOC_MAP_METALNESS") + (description ""))) + + (structs + ((name "Vector2") + (description "Vector2, 2 components") + (fields + ((type "float") + (name "x") + (description "Vector x component")) + ((type "float") + (name "y") + (description "Vector y component")))) + + ((name "Vector3") + (description "Vector3, 3 components") + (fields + ((type "float") + (name "x") + (description "Vector x component")) + ((type "float") + (name "y") + (description "Vector y component")) + ((type "float") + (name "z") + (description "Vector z component")))) + + ((name "Vector4") + (description "Vector4, 4 components") + (fields + ((type "float") + (name "x") + (description "Vector x component")) + ((type "float") + (name "y") + (description "Vector y component")) + ((type "float") + (name "z") + (description "Vector z component")) + ((type "float") + (name "w") + (description "Vector w component")))) + + ((name "Matrix") + (description "Matrix, 4x4 components, column major, OpenGL style, right-handed") + (fields + ((type "float") + (name "m0") + (description "Matrix first row (4 components)")) + ((type "float") + (name "m4") + (description "Matrix first row (4 components)")) + ((type "float") + (name "m8") + (description "Matrix first row (4 components)")) + ((type "float") + (name "m12") + (description "Matrix first row (4 components)")) + ((type "float") + (name "m1") + (description "Matrix second row (4 components)")) + ((type "float") + (name "m5") + (description "Matrix second row (4 components)")) + ((type "float") + (name "m9") + (description "Matrix second row (4 components)")) + ((type "float") + (name "m13") + (description "Matrix second row (4 components)")) + ((type "float") + (name "m2") + (description "Matrix third row (4 components)")) + ((type "float") + (name "m6") + (description "Matrix third row (4 components)")) + ((type "float") + (name "m10") + (description "Matrix third row (4 components)")) + ((type "float") + (name "m14") + (description "Matrix third row (4 components)")) + ((type "float") + (name "m3") + (description "Matrix fourth row (4 components)")) + ((type "float") + (name "m7") + (description "Matrix fourth row (4 components)")) + ((type "float") + (name "m11") + (description "Matrix fourth row (4 components)")) + ((type "float") + (name "m15") + (description "Matrix fourth row (4 components)")))) + + ((name "Color") + (description "Color, 4 components, R8G8B8A8 (32bit)") + (fields + ((type "unsigned char") + (name "r") + (description "Color red value")) + ((type "unsigned char") + (name "g") + (description "Color green value")) + ((type "unsigned char") + (name "b") + (description "Color blue value")) + ((type "unsigned char") + (name "a") + (description "Color alpha value")))) + + ((name "Rectangle") + (description "Rectangle, 4 components") + (fields + ((type "float") + (name "x") + (description "Rectangle top-left corner position x")) + ((type "float") + (name "y") + (description "Rectangle top-left corner position y")) + ((type "float") + (name "width") + (description "Rectangle width")) + ((type "float") + (name "height") + (description "Rectangle height")))) + + ((name "Image") + (description "Image, pixel data stored in CPU memory (RAM)") + (fields + ((type "void *") + (name "data") + (description "Image raw data")) + ((type "int") + (name "width") + (description "Image base width")) + ((type "int") + (name "height") + (description "Image base height")) + ((type "int") + (name "mipmaps") + (description "Mipmap levels, 1 by default")) + ((type "int") + (name "format") + (description "Data format (PixelFormat type)")))) + + ((name "Texture") + (description "Texture, tex data stored in GPU memory (VRAM)") + (fields + ((type "unsigned int") + (name "id") + (description "OpenGL texture id")) + ((type "int") + (name "width") + (description "Texture base width")) + ((type "int") + (name "height") + (description "Texture base height")) + ((type "int") + (name "mipmaps") + (description "Mipmap levels, 1 by default")) + ((type "int") + (name "format") + (description "Data format (PixelFormat type)")))) + + ((name "RenderTexture") + (description "RenderTexture, fbo for texture rendering") + (fields + ((type "unsigned int") + (name "id") + (description "OpenGL framebuffer object id")) + ((type "Texture") + (name "texture") + (description "Color buffer attachment texture")) + ((type "Texture") + (name "depth") + (description "Depth buffer attachment texture")))) + + ((name "NPatchInfo") + (description "NPatchInfo, n-patch layout info") + (fields + ((type "Rectangle") + (name "source") + (description "Texture source rectangle")) + ((type "int") + (name "left") + (description "Left border offset")) + ((type "int") + (name "top") + (description "Top border offset")) + ((type "int") + (name "right") + (description "Right border offset")) + ((type "int") + (name "bottom") + (description "Bottom border offset")) + ((type "int") + (name "layout") + (description "Layout of the n-patch: 3x3, 1x3 or 3x1")))) + + ((name "GlyphInfo") + (description "GlyphInfo, font characters glyphs info") + (fields + ((type "int") + (name "value") + (description "Character value (Unicode)")) + ((type "int") + (name "offsetX") + (description "Character offset X when drawing")) + ((type "int") + (name "offsetY") + (description "Character offset Y when drawing")) + ((type "int") + (name "advanceX") + (description "Character advance position X")) + ((type "Image") + (name "image") + (description "Character image data")))) + + ((name "Font") + (description "Font, font texture and GlyphInfo array data") + (fields + ((type "int") + (name "baseSize") + (description "Base size (default chars height)")) + ((type "int") + (name "glyphCount") + (description "Number of glyph characters")) + ((type "int") + (name "glyphPadding") + (description "Padding around the glyph characters")) + ((type "Texture2D") + (name "texture") + (description "Texture atlas containing the glyphs")) + ((type "Rectangle *") + (name "recs") + (description "Rectangles in texture for the glyphs")) + ((type "GlyphInfo *") + (name "glyphs") + (description "Glyphs info data")))) + + ((name "Camera3D") + (description "Camera, defines position/orientation in 3d space") + (fields + ((type "Vector3") + (name "position") + (description "Camera position")) + ((type "Vector3") + (name "target") + (description "Camera target it looks-at")) + ((type "Vector3") + (name "up") + (description "Camera up vector (rotation over its axis)")) + ((type "float") + (name "fovy") + (description "Camera field-of-view aperture in Y (degrees) in perspective, used as near plane height in world units in orthographic")) + ((type "int") + (name "projection") + (description "Camera projection: CAMERA_PERSPECTIVE or CAMERA_ORTHOGRAPHIC")))) + + ((name "Camera2D") + (description "Camera2D, defines position/orientation in 2d space") + (fields + ((type "Vector2") + (name "offset") + (description "Camera offset (screen space offset from window origin)")) + ((type "Vector2") + (name "target") + (description "Camera target (world space target point that is mapped to screen space offset)")) + ((type "float") + (name "rotation") + (description "Camera rotation in degrees (pivots around target)")) + ((type "float") + (name "zoom") + (description "Camera zoom (scaling around target), must not be set to 0, set to 1.0f for no scale")))) + + ((name "Mesh") + (description "Mesh, vertex data and vao/vbo") + (fields + ((type "int") + (name "vertexCount") + (description "Number of vertices stored in arrays")) + ((type "int") + (name "triangleCount") + (description "Number of triangles stored (indexed or not)")) + ((type "float *") + (name "vertices") + (description "Vertex position (XYZ - 3 components per vertex) (shader-location = 0)")) + ((type "float *") + (name "texcoords") + (description "Vertex texture coordinates (UV - 2 components per vertex) (shader-location = 1)")) + ((type "float *") + (name "texcoords2") + (description "Vertex texture second coordinates (UV - 2 components per vertex) (shader-location = 5)")) + ((type "float *") + (name "normals") + (description "Vertex normals (XYZ - 3 components per vertex) (shader-location = 2)")) + ((type "float *") + (name "tangents") + (description "Vertex tangents (XYZW - 4 components per vertex) (shader-location = 4)")) + ((type "unsigned char *") + (name "colors") + (description "Vertex colors (RGBA - 4 components per vertex) (shader-location = 3)")) + ((type "unsigned short *") + (name "indices") + (description "Vertex indices (in case vertex data comes indexed)")) + ((type "int") + (name "boneCount") + (description "Number of bones (MAX: 256 bones)")) + ((type "unsigned char *") + (name "boneIndices") + (description "Vertex bone indices, up to 4 bones influence by vertex (skinning) (shader-location = 6)")) + ((type "float *") + (name "boneWeights") + (description "Vertex bone weight, up to 4 bones influence by vertex (skinning) (shader-location = 7)")) + ((type "float *") + (name "animVertices") + (description "Animated vertex positions (after bones transformations)")) + ((type "float *") + (name "animNormals") + (description "Animated normals (after bones transformations)")) + ((type "unsigned int") + (name "vaoId") + (description "OpenGL Vertex Array Object id")) + ((type "unsigned int *") + (name "vboId") + (description "OpenGL Vertex Buffer Objects id (default vertex data)")))) + + ((name "Shader") + (description "Shader") + (fields + ((type "unsigned int") + (name "id") + (description "Shader program id")) + ((type "int *") + (name "locs") + (description "Shader locations array (RL_MAX_SHADER_LOCATIONS)")))) + + ((name "MaterialMap") + (description "MaterialMap") + (fields + ((type "Texture2D") + (name "texture") + (description "Material map texture")) + ((type "Color") + (name "color") + (description "Material map color")) + ((type "float") + (name "value") + (description "Material map value")))) + + ((name "Material") + (description "Material, includes shader and maps") + (fields + ((type "Shader") + (name "shader") + (description "Material shader")) + ((type "MaterialMap *") + (name "maps") + (description "Material maps array (MAX_MATERIAL_MAPS)")) + ((type "float[4]") + (name "params") + (description "Material generic parameters (if required)")))) + + ((name "Transform") + (description "Transform, vertex transformation data") + (fields + ((type "Vector3") + (name "translation") + (description "Translation")) + ((type "Quaternion") + (name "rotation") + (description "Rotation")) + ((type "Vector3") + (name "scale") + (description "Scale")))) + + ((name "BoneInfo") + (description "Bone, skeletal animation bone") + (fields + ((type "char[32]") + (name "name") + (description "Bone name")) + ((type "int") + (name "parent") + (description "Bone parent")))) + + ((name "ModelSkeleton") + (description "Skeleton, animation bones hierarchy") + (fields + ((type "int") + (name "boneCount") + (description "Number of bones")) + ((type "BoneInfo *") + (name "bones") + (description "Bones information (skeleton)")) + ((type "ModelAnimPose") + (name "bindPose") + (description "Bones base transformation (Transform[])")))) + + ((name "Model") + (description "Model, meshes, materials and animation data") + (fields + ((type "Matrix") + (name "transform") + (description "Local transform matrix")) + ((type "int") + (name "meshCount") + (description "Number of meshes")) + ((type "int") + (name "materialCount") + (description "Number of materials")) + ((type "Mesh *") + (name "meshes") + (description "Meshes array")) + ((type "Material *") + (name "materials") + (description "Materials array")) + ((type "int *") + (name "meshMaterial") + (description "Mesh material number")) + ((type "ModelSkeleton") + (name "skeleton") + (description "Skeleton for animation")) + ((type "ModelAnimPose") + (name "currentPose") + (description "Current animation pose (Transform[])")) + ((type "Matrix *") + (name "boneMatrices") + (description "Bones animated transformation matrices")))) + + ((name "ModelAnimation") + (description "ModelAnimation, contains a full animation sequence") + (fields + ((type "char[32]") + (name "name") + (description "Animation name")) + ((type "int") + (name "boneCount") + (description "Number of bones (per pose)")) + ((type "int") + (name "keyframeCount") + (description "Number of animation key frames")) + ((type "ModelAnimPose *") + (name "keyframePoses") + (description "Animation sequence keyframe poses [keyframe][pose]")))) + + ((name "Ray") + (description "Ray, ray for raycasting") + (fields + ((type "Vector3") + (name "position") + (description "Ray position (origin)")) + ((type "Vector3") + (name "direction") + (description "Ray direction (normalized)")))) + + ((name "RayCollision") + (description "RayCollision, ray hit information") + (fields + ((type "bool") + (name "hit") + (description "Did the ray hit something?")) + ((type "float") + (name "distance") + (description "Distance to the nearest hit")) + ((type "Vector3") + (name "point") + (description "Point of the nearest hit")) + ((type "Vector3") + (name "normal") + (description "Surface normal of hit")))) + + ((name "BoundingBox") + (description "BoundingBox") + (fields + ((type "Vector3") + (name "min") + (description "Minimum vertex box-corner")) + ((type "Vector3") + (name "max") + (description "Maximum vertex box-corner")))) + + ((name "Wave") + (description "Wave, audio wave data") + (fields + ((type "unsigned int") + (name "frameCount") + (description "Total number of frames (considering channels)")) + ((type "unsigned int") + (name "sampleRate") + (description "Frequency (samples per second)")) + ((type "unsigned int") + (name "sampleSize") + (description "Bit depth (bits per sample): 8, 16, 32 (24 not supported)")) + ((type "unsigned int") + (name "channels") + (description "Number of channels (1-mono, 2-stereo, ...)")) + ((type "void *") + (name "data") + (description "Buffer data pointer")))) + + ((name "AudioStream") + (description "AudioStream, custom audio stream") + (fields + ((type "rAudioBuffer *") + (name "buffer") + (description "Pointer to internal data used by the audio system")) + ((type "rAudioProcessor *") + (name "processor") + (description "Pointer to internal data processor, useful for audio effects")) + ((type "unsigned int") + (name "sampleRate") + (description "Frequency (samples per second)")) + ((type "unsigned int") + (name "sampleSize") + (description "Bit depth (bits per sample): 8, 16, 32 (24 not supported)")) + ((type "unsigned int") + (name "channels") + (description "Number of channels (1-mono, 2-stereo, ...)")))) + + ((name "Sound") + (description "Sound") + (fields + ((type "AudioStream") + (name "stream") + (description "Audio stream")) + ((type "unsigned int") + (name "frameCount") + (description "Total number of frames (considering channels)")))) + + ((name "Music") + (description "Music, audio stream, anything longer than ~10 seconds should be streamed") + (fields + ((type "AudioStream") + (name "stream") + (description "Audio stream")) + ((type "unsigned int") + (name "frameCount") + (description "Total number of frames (considering channels)")) + ((type "bool") + (name "looping") + (description "Music looping enable")) + ((type "int") + (name "ctxType") + (description "Type of music context (audio filetype)")) + ((type "void *") + (name "ctxData") + (description "Audio context data, depends on type")))) + + ((name "VrDeviceInfo") + (description "VrDeviceInfo, Head-Mounted-Display device parameters") + (fields + ((type "int") + (name "hResolution") + (description "Horizontal resolution in pixels")) + ((type "int") + (name "vResolution") + (description "Vertical resolution in pixels")) + ((type "float") + (name "hScreenSize") + (description "Horizontal size in meters")) + ((type "float") + (name "vScreenSize") + (description "Vertical size in meters")) + ((type "float") + (name "eyeToScreenDistance") + (description "Distance between eye and display in meters")) + ((type "float") + (name "lensSeparationDistance") + (description "Lens separation distance in meters")) + ((type "float") + (name "interpupillaryDistance") + (description "IPD (distance between pupils) in meters")) + ((type "float[4]") + (name "lensDistortionValues") + (description "Lens distortion constant parameters")) + ((type "float[4]") + (name "chromaAbCorrection") + (description "Chromatic aberration correction parameters")))) + + ((name "VrStereoConfig") + (description "VrStereoConfig, VR stereo rendering configuration for simulator") + (fields + ((type "Matrix[2]") + (name "projection") + (description "VR projection matrices (per eye)")) + ((type "Matrix[2]") + (name "viewOffset") + (description "VR view offset matrices (per eye)")) + ((type "float[2]") + (name "leftLensCenter") + (description "VR left lens center")) + ((type "float[2]") + (name "rightLensCenter") + (description "VR right lens center")) + ((type "float[2]") + (name "leftScreenCenter") + (description "VR left screen center")) + ((type "float[2]") + (name "rightScreenCenter") + (description "VR right screen center")) + ((type "float[2]") + (name "scale") + (description "VR distortion scale")) + ((type "float[2]") + (name "scaleIn") + (description "VR distortion scale in")))) + + ((name "FilePathList") + (description "File path list") + (fields + ((type "unsigned int") + (name "count") + (description "Filepaths entries count")) + ((type "char **") + (name "paths") + (description "Filepaths entries")))) + + ((name "AutomationEvent") + (description "Automation event") + (fields + ((type "unsigned int") + (name "frame") + (description "Event frame")) + ((type "unsigned int") + (name "type") + (description "Event type (AutomationEventType)")) + ((type "int[4]") + (name "params") + (description "Event parameters (if required)")))) + + ((name "AutomationEventList") + (description "Automation event list") + (fields + ((type "unsigned int") + (name "capacity") + (description "Events max entries (MAX_AUTOMATION_EVENTS)")) + ((type "unsigned int") + (name "count") + (description "Events entries count")) + ((type "AutomationEvent *") + (name "events") + (description "Events entries"))))) + + (aliases + ((type "Vector4") + (name "Quaternion") + (description "Quaternion, 4 components (Vector4 alias)")) + + ((type "Texture") + (name "Texture2D") + (description "Texture2D, same as Texture")) + + ((type "Texture") + (name "TextureCubemap") + (description "TextureCubemap, same as Texture")) + + ((type "RenderTexture") + (name "RenderTexture2D") + (description "RenderTexture2D, same as RenderTexture")) + + ((type "Camera3D") + (name "Camera") + (description "Camera type fallback, defaults to Camera3D")) + + ((type "Transform") + (name "*ModelAnimPose") + (description "Anim pose, an array of Transform[]"))) + + (enums + ((name "ConfigFlags") + (description "System/Window config flags") + (values + ((name "FLAG_VSYNC_HINT") + (value 64) + (description "Set to try enabling V-Sync on GPU")) + + ((name "FLAG_FULLSCREEN_MODE") + (value 2) + (description "Set to run program in fullscreen")) + + ((name "FLAG_WINDOW_RESIZABLE") + (value 4) + (description "Set to allow resizable window")) + + ((name "FLAG_WINDOW_UNDECORATED") + (value 8) + (description "Set to disable window decoration (frame and buttons)")) + + ((name "FLAG_WINDOW_HIDDEN") + (value 128) + (description "Set to hide window")) + + ((name "FLAG_WINDOW_MINIMIZED") + (value 512) + (description "Set to minimize window (iconify)")) + + ((name "FLAG_WINDOW_MAXIMIZED") + (value 1024) + (description "Set to maximize window (expanded to monitor)")) + + ((name "FLAG_WINDOW_UNFOCUSED") + (value 2048) + (description "Set to window non focused")) + + ((name "FLAG_WINDOW_TOPMOST") + (value 4096) + (description "Set to window always on top")) + + ((name "FLAG_WINDOW_ALWAYS_RUN") + (value 256) + (description "Set to allow windows running while minimized")) + + ((name "FLAG_WINDOW_TRANSPARENT") + (value 16) + (description "Set to allow transparent framebuffer")) + + ((name "FLAG_WINDOW_HIGHDPI") + (value 8192) + (description "Set to support HighDPI")) + + ((name "FLAG_WINDOW_MOUSE_PASSTHROUGH") + (value 16384) + (description "Set to support mouse passthrough, only supported when FLAG_WINDOW_UNDECORATED")) + + ((name "FLAG_BORDERLESS_WINDOWED_MODE") + (value 32768) + (description "Set to run program in borderless windowed mode")) + + ((name "FLAG_MSAA_4X_HINT") + (value 32) + (description "Set to try enabling MSAA 4X")) + + ((name "FLAG_INTERLACED_HINT") + (value 65536) + (description "Set to try enabling interlaced video format (for V3D)")))) + + ((name "TraceLogLevel") + (description "Trace log level") + (values + ((name "LOG_ALL") + (value 0) + (description "Display all logs")) + + ((name "LOG_TRACE") + (value 1) + (description "Trace logging, intended for internal use only")) + + ((name "LOG_DEBUG") + (value 2) + (description "Debug logging, used for internal debugging, it should be disabled on release builds")) + + ((name "LOG_INFO") + (value 3) + (description "Info logging, used for program execution info")) + + ((name "LOG_WARNING") + (value 4) + (description "Warning logging, used on recoverable failures")) + + ((name "LOG_ERROR") + (value 5) + (description "Error logging, used on unrecoverable failures")) + + ((name "LOG_FATAL") + (value 6) + (description "Fatal logging, used to abort program: exit(EXIT_FAILURE)")) + + ((name "LOG_NONE") + (value 7) + (description "Disable logging")))) + + ((name "KeyboardKey") + (description "Keyboard keys (US keyboard layout)") + (values + ((name "KEY_NULL") + (value 0) + (description "Key: NULL, used for no key pressed")) + + ((name "KEY_APOSTROPHE") + (value 39) + (description "Key: '")) + + ((name "KEY_COMMA") + (value 44) + (description "Key: ,")) + + ((name "KEY_MINUS") + (value 45) + (description "Key: -")) + + ((name "KEY_PERIOD") + (value 46) + (description "Key: .")) + + ((name "KEY_SLASH") + (value 47) + (description "Key: /")) + + ((name "KEY_ZERO") + (value 48) + (description "Key: 0")) + + ((name "KEY_ONE") + (value 49) + (description "Key: 1")) + + ((name "KEY_TWO") + (value 50) + (description "Key: 2")) + + ((name "KEY_THREE") + (value 51) + (description "Key: 3")) + + ((name "KEY_FOUR") + (value 52) + (description "Key: 4")) + + ((name "KEY_FIVE") + (value 53) + (description "Key: 5")) + + ((name "KEY_SIX") + (value 54) + (description "Key: 6")) + + ((name "KEY_SEVEN") + (value 55) + (description "Key: 7")) + + ((name "KEY_EIGHT") + (value 56) + (description "Key: 8")) + + ((name "KEY_NINE") + (value 57) + (description "Key: 9")) + + ((name "KEY_SEMICOLON") + (value 59) + (description "Key: ;")) + + ((name "KEY_EQUAL") + (value 61) + (description "Key: =")) + + ((name "KEY_A") + (value 65) + (description "Key: A | a")) + + ((name "KEY_B") + (value 66) + (description "Key: B | b")) + + ((name "KEY_C") + (value 67) + (description "Key: C | c")) + + ((name "KEY_D") + (value 68) + (description "Key: D | d")) + + ((name "KEY_E") + (value 69) + (description "Key: E | e")) + + ((name "KEY_F") + (value 70) + (description "Key: F | f")) + + ((name "KEY_G") + (value 71) + (description "Key: G | g")) + + ((name "KEY_H") + (value 72) + (description "Key: H | h")) + + ((name "KEY_I") + (value 73) + (description "Key: I | i")) + + ((name "KEY_J") + (value 74) + (description "Key: J | j")) + + ((name "KEY_K") + (value 75) + (description "Key: K | k")) + + ((name "KEY_L") + (value 76) + (description "Key: L | l")) + + ((name "KEY_M") + (value 77) + (description "Key: M | m")) + + ((name "KEY_N") + (value 78) + (description "Key: N | n")) + + ((name "KEY_O") + (value 79) + (description "Key: O | o")) + + ((name "KEY_P") + (value 80) + (description "Key: P | p")) + + ((name "KEY_Q") + (value 81) + (description "Key: Q | q")) + + ((name "KEY_R") + (value 82) + (description "Key: R | r")) + + ((name "KEY_S") + (value 83) + (description "Key: S | s")) + + ((name "KEY_T") + (value 84) + (description "Key: T | t")) + + ((name "KEY_U") + (value 85) + (description "Key: U | u")) + + ((name "KEY_V") + (value 86) + (description "Key: V | v")) + + ((name "KEY_W") + (value 87) + (description "Key: W | w")) + + ((name "KEY_X") + (value 88) + (description "Key: X | x")) + + ((name "KEY_Y") + (value 89) + (description "Key: Y | y")) + + ((name "KEY_Z") + (value 90) + (description "Key: Z | z")) + + ((name "KEY_LEFT_BRACKET") + (value 91) + (description "Key: [")) + + ((name "KEY_BACKSLASH") + (value 92) + (description "Key: '\\'")) + + ((name "KEY_RIGHT_BRACKET") + (value 93) + (description "Key: ]")) + + ((name "KEY_GRAVE") + (value 96) + (description "Key: `")) + + ((name "KEY_SPACE") + (value 32) + (description "Key: Space")) + + ((name "KEY_ESCAPE") + (value 256) + (description "Key: Esc")) + + ((name "KEY_ENTER") + (value 257) + (description "Key: Enter")) + + ((name "KEY_TAB") + (value 258) + (description "Key: Tab")) + + ((name "KEY_BACKSPACE") + (value 259) + (description "Key: Backspace")) + + ((name "KEY_INSERT") + (value 260) + (description "Key: Ins")) + + ((name "KEY_DELETE") + (value 261) + (description "Key: Del")) + + ((name "KEY_RIGHT") + (value 262) + (description "Key: Cursor right")) + + ((name "KEY_LEFT") + (value 263) + (description "Key: Cursor left")) + + ((name "KEY_DOWN") + (value 264) + (description "Key: Cursor down")) + + ((name "KEY_UP") + (value 265) + (description "Key: Cursor up")) + + ((name "KEY_PAGE_UP") + (value 266) + (description "Key: Page up")) + + ((name "KEY_PAGE_DOWN") + (value 267) + (description "Key: Page down")) + + ((name "KEY_HOME") + (value 268) + (description "Key: Home")) + + ((name "KEY_END") + (value 269) + (description "Key: End")) + + ((name "KEY_CAPS_LOCK") + (value 280) + (description "Key: Caps lock")) + + ((name "KEY_SCROLL_LOCK") + (value 281) + (description "Key: Scroll down")) + + ((name "KEY_NUM_LOCK") + (value 282) + (description "Key: Num lock")) + + ((name "KEY_PRINT_SCREEN") + (value 283) + (description "Key: Print screen")) + + ((name "KEY_PAUSE") + (value 284) + (description "Key: Pause")) + + ((name "KEY_F1") + (value 290) + (description "Key: F1")) + + ((name "KEY_F2") + (value 291) + (description "Key: F2")) + + ((name "KEY_F3") + (value 292) + (description "Key: F3")) + + ((name "KEY_F4") + (value 293) + (description "Key: F4")) + + ((name "KEY_F5") + (value 294) + (description "Key: F5")) + + ((name "KEY_F6") + (value 295) + (description "Key: F6")) + + ((name "KEY_F7") + (value 296) + (description "Key: F7")) + + ((name "KEY_F8") + (value 297) + (description "Key: F8")) + + ((name "KEY_F9") + (value 298) + (description "Key: F9")) + + ((name "KEY_F10") + (value 299) + (description "Key: F10")) + + ((name "KEY_F11") + (value 300) + (description "Key: F11")) + + ((name "KEY_F12") + (value 301) + (description "Key: F12")) + + ((name "KEY_LEFT_SHIFT") + (value 340) + (description "Key: Shift left")) + + ((name "KEY_LEFT_CONTROL") + (value 341) + (description "Key: Control left")) + + ((name "KEY_LEFT_ALT") + (value 342) + (description "Key: Alt left")) + + ((name "KEY_LEFT_SUPER") + (value 343) + (description "Key: Super left")) + + ((name "KEY_RIGHT_SHIFT") + (value 344) + (description "Key: Shift right")) + + ((name "KEY_RIGHT_CONTROL") + (value 345) + (description "Key: Control right")) + + ((name "KEY_RIGHT_ALT") + (value 346) + (description "Key: Alt right")) + + ((name "KEY_RIGHT_SUPER") + (value 347) + (description "Key: Super right")) + + ((name "KEY_KB_MENU") + (value 348) + (description "Key: KB menu")) + + ((name "KEY_KP_0") + (value 320) + (description "Key: Keypad 0")) + + ((name "KEY_KP_1") + (value 321) + (description "Key: Keypad 1")) + + ((name "KEY_KP_2") + (value 322) + (description "Key: Keypad 2")) + + ((name "KEY_KP_3") + (value 323) + (description "Key: Keypad 3")) + + ((name "KEY_KP_4") + (value 324) + (description "Key: Keypad 4")) + + ((name "KEY_KP_5") + (value 325) + (description "Key: Keypad 5")) + + ((name "KEY_KP_6") + (value 326) + (description "Key: Keypad 6")) + + ((name "KEY_KP_7") + (value 327) + (description "Key: Keypad 7")) + + ((name "KEY_KP_8") + (value 328) + (description "Key: Keypad 8")) + + ((name "KEY_KP_9") + (value 329) + (description "Key: Keypad 9")) + + ((name "KEY_KP_DECIMAL") + (value 330) + (description "Key: Keypad .")) + + ((name "KEY_KP_DIVIDE") + (value 331) + (description "Key: Keypad /")) + + ((name "KEY_KP_MULTIPLY") + (value 332) + (description "Key: Keypad *")) + + ((name "KEY_KP_SUBTRACT") + (value 333) + (description "Key: Keypad -")) + + ((name "KEY_KP_ADD") + (value 334) + (description "Key: Keypad +")) + + ((name "KEY_KP_ENTER") + (value 335) + (description "Key: Keypad Enter")) + + ((name "KEY_KP_EQUAL") + (value 336) + (description "Key: Keypad =")) + + ((name "KEY_BACK") + (value 4) + (description "Key: Android back button")) + + ((name "KEY_MENU") + (value 5) + (description "Key: Android menu button")) + + ((name "KEY_VOLUME_UP") + (value 24) + (description "Key: Android volume up button")) + + ((name "KEY_VOLUME_DOWN") + (value 25) + (description "Key: Android volume down button")))) + + ((name "MouseButton") + (description "Mouse buttons") + (values + ((name "MOUSE_BUTTON_LEFT") + (value 0) + (description "Mouse button left")) + + ((name "MOUSE_BUTTON_RIGHT") + (value 1) + (description "Mouse button right")) + + ((name "MOUSE_BUTTON_MIDDLE") + (value 2) + (description "Mouse button middle (pressed wheel)")) + + ((name "MOUSE_BUTTON_SIDE") + (value 3) + (description "Mouse button side (advanced mouse device)")) + + ((name "MOUSE_BUTTON_EXTRA") + (value 4) + (description "Mouse button extra (advanced mouse device)")) + + ((name "MOUSE_BUTTON_FORWARD") + (value 5) + (description "Mouse button forward (advanced mouse device)")) + + ((name "MOUSE_BUTTON_BACK") + (value 6) + (description "Mouse button back (advanced mouse device)")))) + + ((name "MouseCursor") + (description "Mouse cursor") + (values + ((name "MOUSE_CURSOR_DEFAULT") + (value 0) + (description "Default pointer shape")) + + ((name "MOUSE_CURSOR_ARROW") + (value 1) + (description "Arrow shape")) + + ((name "MOUSE_CURSOR_IBEAM") + (value 2) + (description "Text writing cursor shape")) + + ((name "MOUSE_CURSOR_CROSSHAIR") + (value 3) + (description "Cross shape")) + + ((name "MOUSE_CURSOR_POINTING_HAND") + (value 4) + (description "Pointing hand cursor")) + + ((name "MOUSE_CURSOR_RESIZE_EW") + (value 5) + (description "Horizontal resize/move arrow shape")) + + ((name "MOUSE_CURSOR_RESIZE_NS") + (value 6) + (description "Vertical resize/move arrow shape")) + + ((name "MOUSE_CURSOR_RESIZE_NWSE") + (value 7) + (description "Top-left to bottom-right diagonal resize/move arrow shape")) + + ((name "MOUSE_CURSOR_RESIZE_NESW") + (value 8) + (description "The top-right to bottom-left diagonal resize/move arrow shape")) + + ((name "MOUSE_CURSOR_RESIZE_ALL") + (value 9) + (description "The omnidirectional resize/move cursor shape")) + + ((name "MOUSE_CURSOR_NOT_ALLOWED") + (value 10) + (description "The operation-not-allowed shape")))) + + ((name "GamepadButton") + (description "Gamepad buttons") + (values + ((name "GAMEPAD_BUTTON_UNKNOWN") + (value 0) + (description "Unknown button, for error checking")) + + ((name "GAMEPAD_BUTTON_LEFT_FACE_UP") + (value 1) + (description "Gamepad left DPAD up button")) + + ((name "GAMEPAD_BUTTON_LEFT_FACE_RIGHT") + (value 2) + (description "Gamepad left DPAD right button")) + + ((name "GAMEPAD_BUTTON_LEFT_FACE_DOWN") + (value 3) + (description "Gamepad left DPAD down button")) + + ((name "GAMEPAD_BUTTON_LEFT_FACE_LEFT") + (value 4) + (description "Gamepad left DPAD left button")) + + ((name "GAMEPAD_BUTTON_RIGHT_FACE_UP") + (value 5) + (description "Gamepad right button up (i.e. PS3: Triangle, Xbox: Y)")) + + ((name "GAMEPAD_BUTTON_RIGHT_FACE_RIGHT") + (value 6) + (description "Gamepad right button right (i.e. PS3: Circle, Xbox: B)")) + + ((name "GAMEPAD_BUTTON_RIGHT_FACE_DOWN") + (value 7) + (description "Gamepad right button down (i.e. PS3: Cross, Xbox: A)")) + + ((name "GAMEPAD_BUTTON_RIGHT_FACE_LEFT") + (value 8) + (description "Gamepad right button left (i.e. PS3: Square, Xbox: X)")) + + ((name "GAMEPAD_BUTTON_LEFT_TRIGGER_1") + (value 9) + (description "Gamepad top/back trigger left (first), it could be a trailing button")) + + ((name "GAMEPAD_BUTTON_LEFT_TRIGGER_2") + (value 10) + (description "Gamepad top/back trigger left (second), it could be a trailing button")) + + ((name "GAMEPAD_BUTTON_RIGHT_TRIGGER_1") + (value 11) + (description "Gamepad top/back trigger right (first), it could be a trailing button")) + + ((name "GAMEPAD_BUTTON_RIGHT_TRIGGER_2") + (value 12) + (description "Gamepad top/back trigger right (second), it could be a trailing button")) + + ((name "GAMEPAD_BUTTON_MIDDLE_LEFT") + (value 13) + (description "Gamepad center buttons, left one (i.e. PS3: Select)")) + + ((name "GAMEPAD_BUTTON_MIDDLE") + (value 14) + (description "Gamepad center buttons, middle one (i.e. PS3: PS, Xbox: XBOX)")) + + ((name "GAMEPAD_BUTTON_MIDDLE_RIGHT") + (value 15) + (description "Gamepad center buttons, right one (i.e. PS3: Start)")) + + ((name "GAMEPAD_BUTTON_LEFT_THUMB") + (value 16) + (description "Gamepad joystick pressed button left")) + + ((name "GAMEPAD_BUTTON_RIGHT_THUMB") + (value 17) + (description "Gamepad joystick pressed button right")))) + + ((name "GamepadAxis") + (description "Gamepad axes") + (values + ((name "GAMEPAD_AXIS_LEFT_X") + (value 0) + (description "Gamepad left stick X axis")) + + ((name "GAMEPAD_AXIS_LEFT_Y") + (value 1) + (description "Gamepad left stick Y axis")) + + ((name "GAMEPAD_AXIS_RIGHT_X") + (value 2) + (description "Gamepad right stick X axis")) + + ((name "GAMEPAD_AXIS_RIGHT_Y") + (value 3) + (description "Gamepad right stick Y axis")) + + ((name "GAMEPAD_AXIS_LEFT_TRIGGER") + (value 4) + (description "Gamepad back trigger left, pressure level: [1..-1]")) + + ((name "GAMEPAD_AXIS_RIGHT_TRIGGER") + (value 5) + (description "Gamepad back trigger right, pressure level: [1..-1]")))) + + ((name "MaterialMapIndex") + (description "Material map index") + (values + ((name "MATERIAL_MAP_ALBEDO") + (value 0) + (description "Albedo material (same as: MATERIAL_MAP_DIFFUSE)")) + + ((name "MATERIAL_MAP_METALNESS") + (value 1) + (description "Metalness material (same as: MATERIAL_MAP_SPECULAR)")) + + ((name "MATERIAL_MAP_NORMAL") + (value 2) + (description "Normal material")) + + ((name "MATERIAL_MAP_ROUGHNESS") + (value 3) + (description "Roughness material")) + + ((name "MATERIAL_MAP_OCCLUSION") + (value 4) + (description "Ambient occlusion material")) + + ((name "MATERIAL_MAP_EMISSION") + (value 5) + (description "Emission material")) + + ((name "MATERIAL_MAP_HEIGHT") + (value 6) + (description "Heightmap material")) + + ((name "MATERIAL_MAP_CUBEMAP") + (value 7) + (description "Cubemap material (NOTE: Uses GL_TEXTURE_CUBE_MAP)")) + + ((name "MATERIAL_MAP_IRRADIANCE") + (value 8) + (description "Irradiance material (NOTE: Uses GL_TEXTURE_CUBE_MAP)")) + + ((name "MATERIAL_MAP_PREFILTER") + (value 9) + (description "Prefilter material (NOTE: Uses GL_TEXTURE_CUBE_MAP)")) + + ((name "MATERIAL_MAP_BRDF") + (value 10) + (description "Brdf material")))) + + ((name "ShaderLocationIndex") + (description "Shader location index") + (values + ((name "SHADER_LOC_VERTEX_POSITION") + (value 0) + (description "Shader location: vertex attribute: position")) + + ((name "SHADER_LOC_VERTEX_TEXCOORD01") + (value 1) + (description "Shader location: vertex attribute: texcoord01")) + + ((name "SHADER_LOC_VERTEX_TEXCOORD02") + (value 2) + (description "Shader location: vertex attribute: texcoord02")) + + ((name "SHADER_LOC_VERTEX_NORMAL") + (value 3) + (description "Shader location: vertex attribute: normal")) + + ((name "SHADER_LOC_VERTEX_TANGENT") + (value 4) + (description "Shader location: vertex attribute: tangent")) + + ((name "SHADER_LOC_VERTEX_COLOR") + (value 5) + (description "Shader location: vertex attribute: color")) + + ((name "SHADER_LOC_MATRIX_MVP") + (value 6) + (description "Shader location: matrix uniform: model-view-projection")) + + ((name "SHADER_LOC_MATRIX_VIEW") + (value 7) + (description "Shader location: matrix uniform: view (camera transform)")) + + ((name "SHADER_LOC_MATRIX_PROJECTION") + (value 8) + (description "Shader location: matrix uniform: projection")) + + ((name "SHADER_LOC_MATRIX_MODEL") + (value 9) + (description "Shader location: matrix uniform: model (transform)")) + + ((name "SHADER_LOC_MATRIX_NORMAL") + (value 10) + (description "Shader location: matrix uniform: normal")) + + ((name "SHADER_LOC_VECTOR_VIEW") + (value 11) + (description "Shader location: vector uniform: view")) + + ((name "SHADER_LOC_COLOR_DIFFUSE") + (value 12) + (description "Shader location: vector uniform: diffuse color")) + + ((name "SHADER_LOC_COLOR_SPECULAR") + (value 13) + (description "Shader location: vector uniform: specular color")) + + ((name "SHADER_LOC_COLOR_AMBIENT") + (value 14) + (description "Shader location: vector uniform: ambient color")) + + ((name "SHADER_LOC_MAP_ALBEDO") + (value 15) + (description "Shader location: sampler2d texture: albedo (same as: SHADER_LOC_MAP_DIFFUSE)")) + + ((name "SHADER_LOC_MAP_METALNESS") + (value 16) + (description "Shader location: sampler2d texture: metalness (same as: SHADER_LOC_MAP_SPECULAR)")) + + ((name "SHADER_LOC_MAP_NORMAL") + (value 17) + (description "Shader location: sampler2d texture: normal")) + + ((name "SHADER_LOC_MAP_ROUGHNESS") + (value 18) + (description "Shader location: sampler2d texture: roughness")) + + ((name "SHADER_LOC_MAP_OCCLUSION") + (value 19) + (description "Shader location: sampler2d texture: occlusion")) + + ((name "SHADER_LOC_MAP_EMISSION") + (value 20) + (description "Shader location: sampler2d texture: emission")) + + ((name "SHADER_LOC_MAP_HEIGHT") + (value 21) + (description "Shader location: sampler2d texture: heightmap")) + + ((name "SHADER_LOC_MAP_CUBEMAP") + (value 22) + (description "Shader location: samplerCube texture: cubemap")) + + ((name "SHADER_LOC_MAP_IRRADIANCE") + (value 23) + (description "Shader location: samplerCube texture: irradiance")) + + ((name "SHADER_LOC_MAP_PREFILTER") + (value 24) + (description "Shader location: samplerCube texture: prefilter")) + + ((name "SHADER_LOC_MAP_BRDF") + (value 25) + (description "Shader location: sampler2d texture: brdf")) + + ((name "SHADER_LOC_VERTEX_BONEIDS") + (value 26) + (description "Shader location: vertex attribute: bone indices")) + + ((name "SHADER_LOC_VERTEX_BONEWEIGHTS") + (value 27) + (description "Shader location: vertex attribute: bone weights")) + + ((name "SHADER_LOC_MATRIX_BONETRANSFORMS") + (value 28) + (description "Shader location: matrix attribute: bone transforms (animation)")) + + ((name "SHADER_LOC_VERTEX_INSTANCETRANSFORM") + (value 29) + (description "Shader location: vertex attribute: instance transforms")))) + + ((name "ShaderUniformDataType") + (description "Shader uniform data type") + (values + ((name "SHADER_UNIFORM_FLOAT") + (value 0) + (description "Shader uniform type: float")) + + ((name "SHADER_UNIFORM_VEC2") + (value 1) + (description "Shader uniform type: vec2 (2 float)")) + + ((name "SHADER_UNIFORM_VEC3") + (value 2) + (description "Shader uniform type: vec3 (3 float)")) + + ((name "SHADER_UNIFORM_VEC4") + (value 3) + (description "Shader uniform type: vec4 (4 float)")) + + ((name "SHADER_UNIFORM_INT") + (value 4) + (description "Shader uniform type: int")) + + ((name "SHADER_UNIFORM_IVEC2") + (value 5) + (description "Shader uniform type: ivec2 (2 int)")) + + ((name "SHADER_UNIFORM_IVEC3") + (value 6) + (description "Shader uniform type: ivec3 (3 int)")) + + ((name "SHADER_UNIFORM_IVEC4") + (value 7) + (description "Shader uniform type: ivec4 (4 int)")) + + ((name "SHADER_UNIFORM_UINT") + (value 8) + (description "Shader uniform type: unsigned int")) + + ((name "SHADER_UNIFORM_UIVEC2") + (value 9) + (description "Shader uniform type: uivec2 (2 unsigned int)")) + + ((name "SHADER_UNIFORM_UIVEC3") + (value 10) + (description "Shader uniform type: uivec3 (3 unsigned int)")) + + ((name "SHADER_UNIFORM_UIVEC4") + (value 11) + (description "Shader uniform type: uivec4 (4 unsigned int)")) + + ((name "SHADER_UNIFORM_SAMPLER2D") + (value 12) + (description "Shader uniform type: sampler2d")))) + + ((name "ShaderAttributeDataType") + (description "Shader attribute data types") + (values + ((name "SHADER_ATTRIB_FLOAT") + (value 0) + (description "Shader attribute type: float")) + + ((name "SHADER_ATTRIB_VEC2") + (value 1) + (description "Shader attribute type: vec2 (2 float)")) + + ((name "SHADER_ATTRIB_VEC3") + (value 2) + (description "Shader attribute type: vec3 (3 float)")) + + ((name "SHADER_ATTRIB_VEC4") + (value 3) + (description "Shader attribute type: vec4 (4 float)")))) + + ((name "PixelFormat") + (description "Pixel formats") + (values + ((name "PIXELFORMAT_UNCOMPRESSED_GRAYSCALE") + (value 1) + (description "8 bit per pixel (no alpha)")) + + ((name "PIXELFORMAT_UNCOMPRESSED_GRAY_ALPHA") + (value 2) + (description "8*2 bpp (2 channels)")) + + ((name "PIXELFORMAT_UNCOMPRESSED_R5G6B5") + (value 3) + (description "16 bpp")) + + ((name "PIXELFORMAT_UNCOMPRESSED_R8G8B8") + (value 4) + (description "24 bpp")) + + ((name "PIXELFORMAT_UNCOMPRESSED_R5G5B5A1") + (value 5) + (description "16 bpp (1 bit alpha)")) + + ((name "PIXELFORMAT_UNCOMPRESSED_R4G4B4A4") + (value 6) + (description "16 bpp (4 bit alpha)")) + + ((name "PIXELFORMAT_UNCOMPRESSED_R8G8B8A8") + (value 7) + (description "32 bpp")) + + ((name "PIXELFORMAT_UNCOMPRESSED_R32") + (value 8) + (description "32 bpp (1 channel - float)")) + + ((name "PIXELFORMAT_UNCOMPRESSED_R32G32B32") + (value 9) + (description "32*3 bpp (3 channels - float)")) + + ((name "PIXELFORMAT_UNCOMPRESSED_R32G32B32A32") + (value 10) + (description "32*4 bpp (4 channels - float)")) + + ((name "PIXELFORMAT_UNCOMPRESSED_R16") + (value 11) + (description "16 bpp (1 channel - half float)")) + + ((name "PIXELFORMAT_UNCOMPRESSED_R16G16B16") + (value 12) + (description "16*3 bpp (3 channels - half float)")) + + ((name "PIXELFORMAT_UNCOMPRESSED_R16G16B16A16") + (value 13) + (description "16*4 bpp (4 channels - half float)")) + + ((name "PIXELFORMAT_COMPRESSED_DXT1_RGB") + (value 14) + (description "4 bpp (no alpha)")) + + ((name "PIXELFORMAT_COMPRESSED_DXT1_RGBA") + (value 15) + (description "4 bpp (1 bit alpha)")) + + ((name "PIXELFORMAT_COMPRESSED_DXT3_RGBA") + (value 16) + (description "8 bpp")) + + ((name "PIXELFORMAT_COMPRESSED_DXT5_RGBA") + (value 17) + (description "8 bpp")) + + ((name "PIXELFORMAT_COMPRESSED_ETC1_RGB") + (value 18) + (description "4 bpp")) + + ((name "PIXELFORMAT_COMPRESSED_ETC2_RGB") + (value 19) + (description "4 bpp")) + + ((name "PIXELFORMAT_COMPRESSED_ETC2_EAC_RGBA") + (value 20) + (description "8 bpp")) + + ((name "PIXELFORMAT_COMPRESSED_PVRT_RGB") + (value 21) + (description "4 bpp")) + + ((name "PIXELFORMAT_COMPRESSED_PVRT_RGBA") + (value 22) + (description "4 bpp")) + + ((name "PIXELFORMAT_COMPRESSED_ASTC_4x4_RGBA") + (value 23) + (description "8 bpp")) + + ((name "PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA") + (value 24) + (description "2 bpp")))) + + ((name "TextureFilter") + (description "Texture parameters: filter mode") + (values + ((name "TEXTURE_FILTER_POINT") + (value 0) + (description "No filter, pixel approximation")) + + ((name "TEXTURE_FILTER_BILINEAR") + (value 1) + (description "Linear filtering")) + + ((name "TEXTURE_FILTER_TRILINEAR") + (value 2) + (description "Trilinear filtering (linear with mipmaps)")) + + ((name "TEXTURE_FILTER_ANISOTROPIC_4X") + (value 3) + (description "Anisotropic filtering 4x")) + + ((name "TEXTURE_FILTER_ANISOTROPIC_8X") + (value 4) + (description "Anisotropic filtering 8x")) + + ((name "TEXTURE_FILTER_ANISOTROPIC_16X") + (value 5) + (description "Anisotropic filtering 16x")))) + + ((name "TextureWrap") + (description "Texture parameters: wrap mode") + (values + ((name "TEXTURE_WRAP_REPEAT") + (value 0) + (description "Repeats texture in tiled mode")) + + ((name "TEXTURE_WRAP_CLAMP") + (value 1) + (description "Clamps texture to edge pixel in tiled mode")) + + ((name "TEXTURE_WRAP_MIRROR_REPEAT") + (value 2) + (description "Mirrors and repeats the texture in tiled mode")) + + ((name "TEXTURE_WRAP_MIRROR_CLAMP") + (value 3) + (description "Mirrors and clamps to border the texture in tiled mode")))) + + ((name "CubemapLayout") + (description "Cubemap layouts") + (values + ((name "CUBEMAP_LAYOUT_AUTO_DETECT") + (value 0) + (description "Automatically detect layout type")) + + ((name "CUBEMAP_LAYOUT_LINE_VERTICAL") + (value 1) + (description "Layout is defined by a vertical line with faces")) + + ((name "CUBEMAP_LAYOUT_LINE_HORIZONTAL") + (value 2) + (description "Layout is defined by a horizontal line with faces")) + + ((name "CUBEMAP_LAYOUT_CROSS_THREE_BY_FOUR") + (value 3) + (description "Layout is defined by a 3x4 cross with cubemap faces")) + + ((name "CUBEMAP_LAYOUT_CROSS_FOUR_BY_THREE") + (value 4) + (description "Layout is defined by a 4x3 cross with cubemap faces")))) + + ((name "FontType") + (description "Font type, defines generation method") + (values + ((name "FONT_DEFAULT") + (value 0) + (description "Default font generation, anti-aliased")) + + ((name "FONT_BITMAP") + (value 1) + (description "Bitmap font generation, no anti-aliasing")) + + ((name "FONT_SDF") + (value 2) + (description "SDF font generation, requires external shader")))) + + ((name "BlendMode") + (description "Color blending modes (pre-defined)") + (values + ((name "BLEND_ALPHA") + (value 0) + (description "Blend textures considering alpha (default)")) + + ((name "BLEND_ADDITIVE") + (value 1) + (description "Blend textures adding colors")) + + ((name "BLEND_MULTIPLIED") + (value 2) + (description "Blend textures multiplying colors")) + + ((name "BLEND_ADD_COLORS") + (value 3) + (description "Blend textures adding colors (alternative)")) + + ((name "BLEND_SUBTRACT_COLORS") + (value 4) + (description "Blend textures subtracting colors (alternative)")) + + ((name "BLEND_ALPHA_PREMULTIPLY") + (value 5) + (description "Blend premultiplied textures considering alpha")) + + ((name "BLEND_CUSTOM") + (value 6) + (description "Blend textures using custom src/dst factors (use rlSetBlendFactors())")) + + ((name "BLEND_CUSTOM_SEPARATE") + (value 7) + (description "Blend textures using custom rgb/alpha separate src/dst factors (use rlSetBlendFactorsSeparate())")))) + + ((name "Gesture") + (description "Gesture") + (values + ((name "GESTURE_NONE") + (value 0) + (description "No gesture")) + + ((name "GESTURE_TAP") + (value 1) + (description "Tap gesture")) + + ((name "GESTURE_DOUBLETAP") + (value 2) + (description "Double tap gesture")) + + ((name "GESTURE_HOLD") + (value 4) + (description "Hold gesture")) + + ((name "GESTURE_DRAG") + (value 8) + (description "Drag gesture")) + + ((name "GESTURE_SWIPE_RIGHT") + (value 16) + (description "Swipe right gesture")) + + ((name "GESTURE_SWIPE_LEFT") + (value 32) + (description "Swipe left gesture")) + + ((name "GESTURE_SWIPE_UP") + (value 64) + (description "Swipe up gesture")) + + ((name "GESTURE_SWIPE_DOWN") + (value 128) + (description "Swipe down gesture")) + + ((name "GESTURE_PINCH_IN") + (value 256) + (description "Pinch in gesture")) + + ((name "GESTURE_PINCH_OUT") + (value 512) + (description "Pinch out gesture")))) + + ((name "CameraMode") + (description "Camera system modes") + (values + ((name "CAMERA_CUSTOM") + (value 0) + (description "Camera custom, controlled by user (UpdateCamera() does nothing)")) + + ((name "CAMERA_FREE") + (value 1) + (description "Camera free mode")) + + ((name "CAMERA_ORBITAL") + (value 2) + (description "Camera orbital, around target, zoom supported")) + + ((name "CAMERA_FIRST_PERSON") + (value 3) + (description "Camera first person")) + + ((name "CAMERA_THIRD_PERSON") + (value 4) + (description "Camera third person")))) + + ((name "CameraProjection") + (description "Camera projection") + (values + ((name "CAMERA_PERSPECTIVE") + (value 0) + (description "Perspective projection")) + + ((name "CAMERA_ORTHOGRAPHIC") + (value 1) + (description "Orthographic projection")))) + + ((name "NPatchLayout") + (description "N-patch layout") + (values + ((name "NPATCH_NINE_PATCH") + (value 0) + (description "Npatch layout: 3x3 tiles")) + + ((name "NPATCH_THREE_PATCH_VERTICAL") + (value 1) + (description "Npatch layout: 1x3 tiles")) + + ((name "NPATCH_THREE_PATCH_HORIZONTAL") + (value 2) + (description "Npatch layout: 3x1 tiles"))))) + + (callbacks + ((name "TraceLogCallback") + (description "Logging: Redirect trace log messages") + (return-type "void") + (params + ((type "int") (name "logLevel")) + ((type "const char *") (name "text")) + ((type "va_list") (name "args")))) + + ((name "LoadFileDataCallback") + (description "FileIO: Load binary data") + (return-type "unsigned char *") + (params + ((type "const char *") (name "fileName")) + ((type "int *") (name "dataSize")))) + + ((name "SaveFileDataCallback") + (description "FileIO: Save binary data") + (return-type "bool") + (params + ((type "const char *") (name "fileName")) + ((type "const void *") (name "data")) + ((type "int") (name "dataSize")))) + + ((name "LoadFileTextCallback") + (description "FileIO: Load text data") + (return-type "char *") + (params + ((type "const char *") (name "fileName")))) + + ((name "SaveFileTextCallback") + (description "FileIO: Save text data") + (return-type "bool") + (params + ((type "const char *") (name "fileName")) + ((type "const char *") (name "text")))) + + ((name "AudioCallback") + (description "") + (return-type "void") + (params + ((type "void *") (name "bufferData")) + ((type "unsigned int") (name "frames"))))) + + (functions + ((name "InitWindow") + (description "Initialize window and OpenGL context") + (return-type "void") + (params + ((type "int") (name "width")) + ((type "int") (name "height")) + ((type "const char *") (name "title")))) + + ((name "CloseWindow") + (description "Close window and unload OpenGL context") + (return-type "void")) + + ((name "WindowShouldClose") + (description "Check if application should close (KEY_ESCAPE pressed or windows close icon clicked)") + (return-type "bool")) + + ((name "IsWindowReady") + (description "Check if window has been initialized successfully") + (return-type "bool")) + + ((name "IsWindowFullscreen") + (description "Check if window is currently fullscreen") + (return-type "bool")) + + ((name "IsWindowHidden") + (description "Check if window is currently hidden") + (return-type "bool")) + + ((name "IsWindowMinimized") + (description "Check if window is currently minimized") + (return-type "bool")) + + ((name "IsWindowMaximized") + (description "Check if window is currently maximized") + (return-type "bool")) + + ((name "IsWindowFocused") + (description "Check if window is currently focused") + (return-type "bool")) + + ((name "IsWindowResized") + (description "Check if window has been resized last frame") + (return-type "bool")) + + ((name "IsWindowState") + (description "Check if one specific window flag is enabled") + (return-type "bool") + (params + ((type "unsigned int") (name "flag")))) + + ((name "SetWindowState") + (description "Set window configuration state using flags") + (return-type "void") + (params + ((type "unsigned int") (name "flags")))) + + ((name "ClearWindowState") + (description "Clear window configuration state flags") + (return-type "void") + (params + ((type "unsigned int") (name "flags")))) + + ((name "ToggleFullscreen") + (description "Toggle window state: fullscreen/windowed, resizes monitor to match window resolution") + (return-type "void")) + + ((name "ToggleBorderlessWindowed") + (description "Toggle window state: borderless windowed, resizes window to match monitor resolution") + (return-type "void")) + + ((name "MaximizeWindow") + (description "Set window state: maximized, if resizable") + (return-type "void")) + + ((name "MinimizeWindow") + (description "Set window state: minimized, if resizable") + (return-type "void")) + + ((name "RestoreWindow") + (description "Restore window from being minimized/maximized") + (return-type "void")) + + ((name "SetWindowIcon") + (description "Set icon for window (single image, RGBA 32bit)") + (return-type "void") + (params + ((type "Image") (name "image")))) + + ((name "SetWindowIcons") + (description "Set icon for window (multiple images, RGBA 32bit)") + (return-type "void") + (params + ((type "Image *") (name "images")) + ((type "int") (name "count")))) + + ((name "SetWindowTitle") + (description "Set title for window") + (return-type "void") + (params + ((type "const char *") (name "title")))) + + ((name "SetWindowPosition") + (description "Set window position on screen") + (return-type "void") + (params + ((type "int") (name "x")) + ((type "int") (name "y")))) + + ((name "SetWindowMonitor") + (description "Set monitor for the current window") + (return-type "void") + (params + ((type "int") (name "monitor")))) + + ((name "SetWindowMinSize") + (description "Set window minimum dimensions (for FLAG_WINDOW_RESIZABLE)") + (return-type "void") + (params + ((type "int") (name "width")) + ((type "int") (name "height")))) + + ((name "SetWindowMaxSize") + (description "Set window maximum dimensions (for FLAG_WINDOW_RESIZABLE)") + (return-type "void") + (params + ((type "int") (name "width")) + ((type "int") (name "height")))) + + ((name "SetWindowSize") + (description "Set window dimensions") + (return-type "void") + (params + ((type "int") (name "width")) + ((type "int") (name "height")))) + + ((name "SetWindowOpacity") + (description "Set window opacity [0.0f..1.0f]") + (return-type "void") + (params + ((type "float") (name "opacity")))) + + ((name "SetWindowFocused") + (description "Set window focused") + (return-type "void")) + + ((name "GetWindowHandle") + (description "Get native window handle") + (return-type "void *")) + + ((name "GetScreenWidth") + (description "Get current screen width") + (return-type "int")) + + ((name "GetScreenHeight") + (description "Get current screen height") + (return-type "int")) + + ((name "GetRenderWidth") + (description "Get current render width (it considers HiDPI)") + (return-type "int")) + + ((name "GetRenderHeight") + (description "Get current render height (it considers HiDPI)") + (return-type "int")) + + ((name "GetMonitorCount") + (description "Get number of connected monitors") + (return-type "int")) + + ((name "GetCurrentMonitor") + (description "Get current monitor where window is placed") + (return-type "int")) + + ((name "GetMonitorPosition") + (description "Get specified monitor position") + (return-type "Vector2") + (params + ((type "int") (name "monitor")))) + + ((name "GetMonitorWidth") + (description "Get specified monitor width (current video mode used by monitor)") + (return-type "int") + (params + ((type "int") (name "monitor")))) + + ((name "GetMonitorHeight") + (description "Get specified monitor height (current video mode used by monitor)") + (return-type "int") + (params + ((type "int") (name "monitor")))) + + ((name "GetMonitorPhysicalWidth") + (description "Get specified monitor physical width in millimetres") + (return-type "int") + (params + ((type "int") (name "monitor")))) + + ((name "GetMonitorPhysicalHeight") + (description "Get specified monitor physical height in millimetres") + (return-type "int") + (params + ((type "int") (name "monitor")))) + + ((name "GetMonitorRefreshRate") + (description "Get specified monitor refresh rate") + (return-type "int") + (params + ((type "int") (name "monitor")))) + + ((name "GetWindowPosition") + (description "Get window position XY on monitor") + (return-type "Vector2")) + + ((name "GetWindowScaleDPI") + (description "Get window scale DPI factor") + (return-type "Vector2")) + + ((name "GetMonitorName") + (description "Get the human-readable, UTF-8 encoded name of the specified monitor") + (return-type "const char *") + (params + ((type "int") (name "monitor")))) + + ((name "SetClipboardText") + (description "Set clipboard text content") + (return-type "void") + (params + ((type "const char *") (name "text")))) + + ((name "GetClipboardText") + (description "Get clipboard text content") + (return-type "const char *")) + + ((name "GetClipboardImage") + (description "Get clipboard image content") + (return-type "Image")) + + ((name "EnableEventWaiting") + (description "Enable waiting for events on EndDrawing(), no automatic event polling") + (return-type "void")) + + ((name "DisableEventWaiting") + (description "Disable waiting for events on EndDrawing(), automatic events polling") + (return-type "void")) + + ((name "ShowCursor") + (description "Show cursor") + (return-type "void")) + + ((name "HideCursor") + (description "Hide cursor") + (return-type "void")) + + ((name "IsCursorHidden") + (description "Check if cursor is not visible") + (return-type "bool")) + + ((name "EnableCursor") + (description "Enable cursor (unlock cursor)") + (return-type "void")) + + ((name "DisableCursor") + (description "Disable cursor (lock cursor)") + (return-type "void")) + + ((name "IsCursorOnScreen") + (description "Check if cursor is on the screen") + (return-type "bool")) + + ((name "ClearBackground") + (description "Clear background (framebuffer) to color") + (return-type "void") + (params + ((type "Color") (name "color")))) + + ((name "BeginDrawing") + (description "Begin canvas (framebuffer) drawing") + (return-type "void")) + + ((name "EndDrawing") + (description "End canvas (framebuffer) drawing and swap buffers (double buffering)") + (return-type "void")) + + ((name "BeginMode2D") + (description "Begin 2D mode with custom camera (2D)") + (return-type "void") + (params + ((type "Camera2D") (name "camera")))) + + ((name "EndMode2D") + (description "End 2D mode with custom camera") + (return-type "void")) + + ((name "BeginMode3D") + (description "Begin 3D mode with custom camera (3D)") + (return-type "void") + (params + ((type "Camera3D") (name "camera")))) + + ((name "EndMode3D") + (description "End 3D mode and returns to default 2D orthographic mode") + (return-type "void")) + + ((name "BeginTextureMode") + (description "Begin drawing to render texture") + (return-type "void") + (params + ((type "RenderTexture2D") (name "target")))) + + ((name "EndTextureMode") + (description "End drawing to render texture") + (return-type "void")) + + ((name "BeginShaderMode") + (description "Begin custom shader drawing") + (return-type "void") + (params + ((type "Shader") (name "shader")))) + + ((name "EndShaderMode") + (description "End custom shader drawing (use default shader)") + (return-type "void")) + + ((name "BeginBlendMode") + (description "Begin blending mode (alpha, additive, multiplied, subtract, custom)") + (return-type "void") + (params + ((type "int") (name "mode")))) + + ((name "EndBlendMode") + (description "End blending mode (reset to default: alpha blending)") + (return-type "void")) + + ((name "BeginScissorMode") + (description "Begin scissor mode (define screen area for following drawing)") + (return-type "void") + (params + ((type "int") (name "x")) + ((type "int") (name "y")) + ((type "int") (name "width")) + ((type "int") (name "height")))) + + ((name "EndScissorMode") + (description "End scissor mode") + (return-type "void")) + + ((name "BeginVrStereoMode") + (description "Begin stereo rendering (requires VR simulator)") + (return-type "void") + (params + ((type "VrStereoConfig") (name "config")))) + + ((name "EndVrStereoMode") + (description "End stereo rendering (requires VR simulator)") + (return-type "void")) + + ((name "LoadVrStereoConfig") + (description "Load VR stereo config for VR simulator device parameters") + (return-type "VrStereoConfig") + (params + ((type "VrDeviceInfo") (name "device")))) + + ((name "UnloadVrStereoConfig") + (description "Unload VR stereo config") + (return-type "void") + (params + ((type "VrStereoConfig") (name "config")))) + + ((name "LoadShader") + (description "Load shader from files and bind default locations") + (return-type "Shader") + (params + ((type "const char *") (name "vsFileName")) + ((type "const char *") (name "fsFileName")))) + + ((name "LoadShaderFromMemory") + (description "Load shader from code strings and bind default locations") + (return-type "Shader") + (params + ((type "const char *") (name "vsCode")) + ((type "const char *") (name "fsCode")))) + + ((name "IsShaderValid") + (description "Check if shader is valid (loaded on GPU)") + (return-type "bool") + (params + ((type "Shader") (name "shader")))) + + ((name "GetShaderLocation") + (description "Get shader uniform location") + (return-type "int") + (params + ((type "Shader") (name "shader")) + ((type "const char *") (name "uniformName")))) + + ((name "GetShaderLocationAttrib") + (description "Get shader attribute location") + (return-type "int") + (params + ((type "Shader") (name "shader")) + ((type "const char *") (name "attribName")))) + + ((name "SetShaderValue") + (description "Set shader uniform value") + (return-type "void") + (params + ((type "Shader") (name "shader")) + ((type "int") (name "locIndex")) + ((type "const void *") (name "value")) + ((type "int") (name "uniformType")))) + + ((name "SetShaderValueV") + (description "Set shader uniform value vector") + (return-type "void") + (params + ((type "Shader") (name "shader")) + ((type "int") (name "locIndex")) + ((type "const void *") (name "value")) + ((type "int") (name "uniformType")) + ((type "int") (name "count")))) + + ((name "SetShaderValueMatrix") + (description "Set shader uniform value (matrix 4x4)") + (return-type "void") + (params + ((type "Shader") (name "shader")) + ((type "int") (name "locIndex")) + ((type "Matrix") (name "mat")))) + + ((name "SetShaderValueTexture") + (description "Set shader uniform value and bind the texture (sampler2d)") + (return-type "void") + (params + ((type "Shader") (name "shader")) + ((type "int") (name "locIndex")) + ((type "Texture2D") (name "texture")))) + + ((name "UnloadShader") + (description "Unload shader from GPU memory (VRAM)") + (return-type "void") + (params + ((type "Shader") (name "shader")))) + + ((name "GetScreenToWorldRay") + (description "Get a ray trace from screen position (i.e mouse)") + (return-type "Ray") + (params + ((type "Vector2") (name "position")) + ((type "Camera") (name "camera")))) + + ((name "GetScreenToWorldRayEx") + (description "Get a ray trace from screen position (i.e mouse) in a viewport") + (return-type "Ray") + (params + ((type "Vector2") (name "position")) + ((type "Camera") (name "camera")) + ((type "int") (name "width")) + ((type "int") (name "height")))) + + ((name "GetWorldToScreen") + (description "Get screen space position for a 3d world space position") + (return-type "Vector2") + (params + ((type "Vector3") (name "position")) + ((type "Camera") (name "camera")))) + + ((name "GetWorldToScreenEx") + (description "Get sized screen space position for a 3d world space position") + (return-type "Vector2") + (params + ((type "Vector3") (name "position")) + ((type "Camera") (name "camera")) + ((type "int") (name "width")) + ((type "int") (name "height")))) + + ((name "GetWorldToScreen2D") + (description "Get screen space position for a 2d camera world space position") + (return-type "Vector2") + (params + ((type "Vector2") (name "position")) + ((type "Camera2D") (name "camera")))) + + ((name "GetScreenToWorld2D") + (description "Get world space position for a 2d camera screen space position") + (return-type "Vector2") + (params + ((type "Vector2") (name "position")) + ((type "Camera2D") (name "camera")))) + + ((name "GetCameraMatrix") + (description "Get camera transform matrix (view matrix)") + (return-type "Matrix") + (params + ((type "Camera") (name "camera")))) + + ((name "GetCameraMatrix2D") + (description "Get camera 2d transform matrix") + (return-type "Matrix") + (params + ((type "Camera2D") (name "camera")))) + + ((name "SetTargetFPS") + (description "Set target FPS (maximum)") + (return-type "void") + (params + ((type "int") (name "fps")))) + + ((name "GetFrameTime") + (description "Get time in seconds for last frame drawn (delta time)") + (return-type "float")) + + ((name "GetTime") + (description "Get elapsed time in seconds since InitWindow()") + (return-type "double")) + + ((name "GetFPS") + (description "Get current FPS") + (return-type "int")) + + ((name "SwapScreenBuffer") + (description "Swap back buffer with front buffer (screen drawing)") + (return-type "void")) + + ((name "PollInputEvents") + (description "Register all input events") + (return-type "void")) + + ((name "WaitTime") + (description "Wait for some time (halt program execution)") + (return-type "void") + (params + ((type "double") (name "seconds")))) + + ((name "SetRandomSeed") + (description "Set the seed for the random number generator") + (return-type "void") + (params + ((type "unsigned int") (name "seed")))) + + ((name "GetRandomValue") + (description "Get a random value between min and max (both included)") + (return-type "int") + (params + ((type "int") (name "min")) + ((type "int") (name "max")))) + + ((name "LoadRandomSequence") + (description "Load random values sequence, no values repeated") + (return-type "int *") + (params + ((type "unsigned int") (name "count")) + ((type "int") (name "min")) + ((type "int") (name "max")))) + + ((name "UnloadRandomSequence") + (description "Unload random values sequence") + (return-type "void") + (params + ((type "int *") (name "sequence")))) + + ((name "TakeScreenshot") + (description "Takes a screenshot of current screen (filename extension defines format)") + (return-type "void") + (params + ((type "const char *") (name "fileName")))) + + ((name "SetConfigFlags") + (description "Set up init configuration flags (view FLAGS)") + (return-type "void") + (params + ((type "unsigned int") (name "flags")))) + + ((name "OpenURL") + (description "Open URL with default system browser (if available)") + (return-type "void") + (params + ((type "const char *") (name "url")))) + + ((name "SetTraceLogLevel") + (description "Set the current threshold (minimum) log level") + (return-type "void") + (params + ((type "int") (name "logLevel")))) + + ((name "TraceLog") + (description "Show trace log messages (LOG_DEBUG, LOG_INFO, LOG_WARNING, LOG_ERROR...)") + (return-type "void") + (params + ((type "int") (name "logLevel")) + ((type "const char *") (name "text")) + ((type "...") (name "args")))) + + ((name "SetTraceLogCallback") + (description "Set custom trace log") + (return-type "void") + (params + ((type "TraceLogCallback") (name "callback")))) + + ((name "MemAlloc") + (description "Internal memory allocator") + (return-type "void *") + (params + ((type "unsigned int") (name "size")))) + + ((name "MemRealloc") + (description "Internal memory reallocator") + (return-type "void *") + (params + ((type "void *") (name "ptr")) + ((type "unsigned int") (name "size")))) + + ((name "MemFree") + (description "Internal memory free") + (return-type "void") + (params + ((type "void *") (name "ptr")))) + + ((name "LoadFileData") + (description "Load file data as byte array (read)") + (return-type "unsigned char *") + (params + ((type "const char *") (name "fileName")) + ((type "int *") (name "dataSize")))) + + ((name "UnloadFileData") + (description "Unload file data allocated by LoadFileData()") + (return-type "void") + (params + ((type "unsigned char *") (name "data")))) + + ((name "SaveFileData") + (description "Save data to file from byte array (write), returns true on success") + (return-type "bool") + (params + ((type "const char *") (name "fileName")) + ((type "const void *") (name "data")) + ((type "int") (name "dataSize")))) + + ((name "ExportDataAsCode") + (description "Export data to code (.h), returns true on success") + (return-type "bool") + (params + ((type "const unsigned char *") (name "data")) + ((type "int") (name "dataSize")) + ((type "const char *") (name "fileName")))) + + ((name "LoadFileText") + (description "Load text data from file (read), returns a '\\0' terminated string") + (return-type "char *") + (params + ((type "const char *") (name "fileName")))) + + ((name "UnloadFileText") + (description "Unload file text data allocated by LoadFileText()") + (return-type "void") + (params + ((type "char *") (name "text")))) + + ((name "SaveFileText") + (description "Save text data to file (write), string must be '\\0' terminated, returns true on success") + (return-type "bool") + (params + ((type "const char *") (name "fileName")) + ((type "const char *") (name "text")))) + + ((name "SetLoadFileDataCallback") + (description "Set custom file binary data loader") + (return-type "void") + (params + ((type "LoadFileDataCallback") (name "callback")))) + + ((name "SetSaveFileDataCallback") + (description "Set custom file binary data saver") + (return-type "void") + (params + ((type "SaveFileDataCallback") (name "callback")))) + + ((name "SetLoadFileTextCallback") + (description "Set custom file text data loader") + (return-type "void") + (params + ((type "LoadFileTextCallback") (name "callback")))) + + ((name "SetSaveFileTextCallback") + (description "Set custom file text data saver") + (return-type "void") + (params + ((type "SaveFileTextCallback") (name "callback")))) + + ((name "FileRename") + (description "Rename file (if exists), returns 0 on success") + (return-type "int") + (params + ((type "const char *") (name "fileName")) + ((type "const char *") (name "fileRename")))) + + ((name "FileRemove") + (description "Remove file (if exists), returns 0 on success") + (return-type "int") + (params + ((type "const char *") (name "fileName")))) + + ((name "FileCopy") + (description "Copy file from one path to another, dstPath created if it doesn't exist, returns 0 on success") + (return-type "int") + (params + ((type "const char *") (name "srcPath")) + ((type "const char *") (name "dstPath")))) + + ((name "FileMove") + (description "Move file from one directory to another, dstPath created if it doesn't exist, returns 0 on success") + (return-type "int") + (params + ((type "const char *") (name "srcPath")) + ((type "const char *") (name "dstPath")))) + + ((name "FileTextReplace") + (description "Replace text in an existing file, returns 0 on success") + (return-type "int") + (params + ((type "const char *") (name "fileName")) + ((type "const char *") (name "search")) + ((type "const char *") (name "replacement")))) + + ((name "FileTextFindIndex") + (description "Find text in existing file, returns -1 if index not found or index otherwise") + (return-type "int") + (params + ((type "const char *") (name "fileName")) + ((type "const char *") (name "search")))) + + ((name "FileExists") + (description "Check if file exists") + (return-type "bool") + (params + ((type "const char *") (name "fileName")))) + + ((name "DirectoryExists") + (description "Check if directory path exists") + (return-type "bool") + (params + ((type "const char *") (name "dirPath")))) + + ((name "IsFileExtension") + (description "Check file extension (recommended include point: .png, .wav)") + (return-type "bool") + (params + ((type "const char *") (name "fileName")) + ((type "const char *") (name "ext")))) + + ((name "GetFileLength") + (description "Get file length in bytes (NOTE: GetFileSize() conflicts with windows.h)") + (return-type "int") + (params + ((type "const char *") (name "fileName")))) + + ((name "GetFileModTime") + (description "Get file modification time (last write time)") + (return-type "long") + (params + ((type "const char *") (name "fileName")))) + + ((name "GetFileExtension") + (description "Get pointer to extension for a filename string (includes dot: '.png')") + (return-type "const char *") + (params + ((type "const char *") (name "fileName")))) + + ((name "GetFileName") + (description "Get pointer to filename for a path string") + (return-type "const char *") + (params + ((type "const char *") (name "filePath")))) + + ((name "GetFileNameWithoutExt") + (description "Get filename string without extension (uses static string)") + (return-type "const char *") + (params + ((type "const char *") (name "filePath")))) + + ((name "GetDirectoryPath") + (description "Get full path for a given fileName with path (uses static string)") + (return-type "const char *") + (params + ((type "const char *") (name "filePath")))) + + ((name "GetPrevDirectoryPath") + (description "Get previous directory path for a given path (uses static string)") + (return-type "const char *") + (params + ((type "const char *") (name "dirPath")))) + + ((name "GetWorkingDirectory") + (description "Get current working directory (uses static string)") + (return-type "const char *")) + + ((name "GetApplicationDirectory") + (description "Get the directory of the running application (uses static string)") + (return-type "const char *")) + + ((name "MakeDirectory") + (description "Create directories (including full path requested), returns 0 on success") + (return-type "int") + (params + ((type "const char *") (name "dirPath")))) + + ((name "ChangeDirectory") + (description "Change working directory, returns 0 on success") + (return-type "int") + (params + ((type "const char *") (name "dirPath")))) + + ((name "IsPathFile") + (description "Check if given path is a file or a directory") + (return-type "bool") + (params + ((type "const char *") (name "path")))) + + ((name "IsFileNameValid") + (description "Check if fileName is valid for the platform/OS") + (return-type "bool") + (params + ((type "const char *") (name "fileName")))) + + ((name "LoadDirectoryFiles") + (description "Load directory filepaths, files and directories, no subdirs scan") + (return-type "FilePathList") + (params + ((type "const char *") (name "dirPath")))) + + ((name "LoadDirectoryFilesEx") + (description "Load directory filepaths with extension filtering and subdir scan; some filters available: '*.*','FILES*','DIRS*'") + (return-type "FilePathList") + (params + ((type "const char *") (name "basePath")) + ((type "const char *") (name "filter")) + ((type "bool") (name "scanSubdirs")))) + + ((name "UnloadDirectoryFiles") + (description "Unload filepaths") + (return-type "void") + (params + ((type "FilePathList") (name "files")))) + + ((name "IsFileDropped") + (description "Check if file has been dropped into window") + (return-type "bool")) + + ((name "LoadDroppedFiles") + (description "Load dropped filepaths") + (return-type "FilePathList")) + + ((name "UnloadDroppedFiles") + (description "Unload dropped filepaths") + (return-type "void") + (params + ((type "FilePathList") (name "files")))) + + ((name "GetDirectoryFileCount") + (description "Get the file count in a directory") + (return-type "unsigned int") + (params + ((type "const char *") (name "dirPath")))) + + ((name "GetDirectoryFileCountEx") + (description "Get the file count in a directory with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result") + (return-type "unsigned int") + (params + ((type "const char *") (name "basePath")) + ((type "const char *") (name "filter")) + ((type "bool") (name "scanSubdirs")))) + + ((name "CompressData") + (description "Compress data (DEFLATE algorithm), memory must be MemFree()") + (return-type "unsigned char *") + (params + ((type "const unsigned char *") (name "data")) + ((type "int") (name "dataSize")) + ((type "int *") (name "compDataSize")))) + + ((name "DecompressData") + (description "Decompress data (DEFLATE algorithm), memory must be MemFree()") + (return-type "unsigned char *") + (params + ((type "const unsigned char *") (name "compData")) + ((type "int") (name "compDataSize")) + ((type "int *") (name "dataSize")))) + + ((name "EncodeDataBase64") + (description "Encode data to Base64 string (includes NULL terminator), memory must be MemFree()") + (return-type "char *") + (params + ((type "const unsigned char *") (name "data")) + ((type "int") (name "dataSize")) + ((type "int *") (name "outputSize")))) + + ((name "DecodeDataBase64") + (description "Decode Base64 string (expected NULL terminated), memory must be MemFree()") + (return-type "unsigned char *") + (params + ((type "const char *") (name "text")) + ((type "int *") (name "outputSize")))) + + ((name "ComputeCRC32") + (description "Compute CRC32 hash code") + (return-type "unsigned int") + (params + ((type "const unsigned char *") (name "data")) + ((type "int") (name "dataSize")))) + + ((name "ComputeMD5") + (description "Compute MD5 hash code, returns static int[4] (16 bytes)") + (return-type "unsigned int *") + (params + ((type "const unsigned char *") (name "data")) + ((type "int") (name "dataSize")))) + + ((name "ComputeSHA1") + (description "Compute SHA1 hash code, returns static int[5] (20 bytes)") + (return-type "unsigned int *") + (params + ((type "const unsigned char *") (name "data")) + ((type "int") (name "dataSize")))) + + ((name "ComputeSHA256") + (description "Compute SHA256 hash code, returns static int[8] (32 bytes)") + (return-type "unsigned int *") + (params + ((type "const unsigned char *") (name "data")) + ((type "int") (name "dataSize")))) + + ((name "LoadAutomationEventList") + (description "Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS") + (return-type "AutomationEventList") + (params + ((type "const char *") (name "fileName")))) + + ((name "UnloadAutomationEventList") + (description "Unload automation events list from file") + (return-type "void") + (params + ((type "AutomationEventList") (name "list")))) + + ((name "ExportAutomationEventList") + (description "Export automation events list as text file") + (return-type "bool") + (params + ((type "AutomationEventList") (name "list")) + ((type "const char *") (name "fileName")))) + + ((name "SetAutomationEventList") + (description "Set automation event list to record to") + (return-type "void") + (params + ((type "AutomationEventList *") (name "list")))) + + ((name "SetAutomationEventBaseFrame") + (description "Set automation event internal base frame to start recording") + (return-type "void") + (params + ((type "int") (name "frame")))) + + ((name "StartAutomationEventRecording") + (description "Start recording automation events (AutomationEventList must be set)") + (return-type "void")) + + ((name "StopAutomationEventRecording") + (description "Stop recording automation events") + (return-type "void")) + + ((name "PlayAutomationEvent") + (description "Play a recorded automation event") + (return-type "void") + (params + ((type "AutomationEvent") (name "event")))) + + ((name "IsKeyPressed") + (description "Check if key has been pressed once") + (return-type "bool") + (params + ((type "int") (name "key")))) + + ((name "IsKeyPressedRepeat") + (description "Check if key has been pressed again") + (return-type "bool") + (params + ((type "int") (name "key")))) + + ((name "IsKeyDown") + (description "Check if key is being pressed") + (return-type "bool") + (params + ((type "int") (name "key")))) + + ((name "IsKeyReleased") + (description "Check if key has been released once") + (return-type "bool") + (params + ((type "int") (name "key")))) + + ((name "IsKeyUp") + (description "Check if key is NOT being pressed") + (return-type "bool") + (params + ((type "int") (name "key")))) + + ((name "GetKeyPressed") + (description "Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty") + (return-type "int")) + + ((name "GetCharPressed") + (description "Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty") + (return-type "int")) + + ((name "GetKeyName") + (description "Get name of a QWERTY key on the current keyboard layout (eg returns string 'q' for KEY_A on an AZERTY keyboard)") + (return-type "const char *") + (params + ((type "int") (name "key")))) + + ((name "SetExitKey") + (description "Set a custom key to exit program (default is ESC)") + (return-type "void") + (params + ((type "int") (name "key")))) + + ((name "IsGamepadAvailable") + (description "Check if gamepad is available") + (return-type "bool") + (params + ((type "int") (name "gamepad")))) + + ((name "GetGamepadName") + (description "Get gamepad internal name id") + (return-type "const char *") + (params + ((type "int") (name "gamepad")))) + + ((name "IsGamepadButtonPressed") + (description "Check if gamepad button has been pressed once") + (return-type "bool") + (params + ((type "int") (name "gamepad")) + ((type "int") (name "button")))) + + ((name "IsGamepadButtonDown") + (description "Check if gamepad button is being pressed") + (return-type "bool") + (params + ((type "int") (name "gamepad")) + ((type "int") (name "button")))) + + ((name "IsGamepadButtonReleased") + (description "Check if gamepad button has been released once") + (return-type "bool") + (params + ((type "int") (name "gamepad")) + ((type "int") (name "button")))) + + ((name "IsGamepadButtonUp") + (description "Check if gamepad button is NOT being pressed") + (return-type "bool") + (params + ((type "int") (name "gamepad")) + ((type "int") (name "button")))) + + ((name "GetGamepadButtonPressed") + (description "Get the last gamepad button pressed") + (return-type "int")) + + ((name "GetGamepadAxisCount") + (description "Get axis count for a gamepad") + (return-type "int") + (params + ((type "int") (name "gamepad")))) + + ((name "GetGamepadAxisMovement") + (description "Get movement value for a gamepad axis") + (return-type "float") + (params + ((type "int") (name "gamepad")) + ((type "int") (name "axis")))) + + ((name "SetGamepadMappings") + (description "Set internal gamepad mappings (SDL_GameControllerDB)") + (return-type "int") + (params + ((type "const char *") (name "mappings")))) + + ((name "SetGamepadVibration") + (description "Set gamepad vibration for both motors (duration in seconds)") + (return-type "void") + (params + ((type "int") (name "gamepad")) + ((type "float") (name "leftMotor")) + ((type "float") (name "rightMotor")) + ((type "float") (name "duration")))) + + ((name "IsMouseButtonPressed") + (description "Check if mouse button has been pressed once") + (return-type "bool") + (params + ((type "int") (name "button")))) + + ((name "IsMouseButtonDown") + (description "Check if mouse button is being pressed") + (return-type "bool") + (params + ((type "int") (name "button")))) + + ((name "IsMouseButtonReleased") + (description "Check if mouse button has been released once") + (return-type "bool") + (params + ((type "int") (name "button")))) + + ((name "IsMouseButtonUp") + (description "Check if mouse button is NOT being pressed") + (return-type "bool") + (params + ((type "int") (name "button")))) + + ((name "GetMouseX") + (description "Get mouse position X") + (return-type "int")) + + ((name "GetMouseY") + (description "Get mouse position Y") + (return-type "int")) + + ((name "GetMousePosition") + (description "Get mouse position XY") + (return-type "Vector2")) + + ((name "GetMouseDelta") + (description "Get mouse delta between frames") + (return-type "Vector2")) + + ((name "SetMousePosition") + (description "Set mouse position XY") + (return-type "void") + (params + ((type "int") (name "x")) + ((type "int") (name "y")))) + + ((name "SetMouseOffset") + (description "Set mouse offset") + (return-type "void") + (params + ((type "int") (name "offsetX")) + ((type "int") (name "offsetY")))) + + ((name "SetMouseScale") + (description "Set mouse scaling") + (return-type "void") + (params + ((type "float") (name "scaleX")) + ((type "float") (name "scaleY")))) + + ((name "GetMouseWheelMove") + (description "Get mouse wheel movement for X or Y, whichever is larger") + (return-type "float")) + + ((name "GetMouseWheelMoveV") + (description "Get mouse wheel movement for both X and Y") + (return-type "Vector2")) + + ((name "SetMouseCursor") + (description "Set mouse cursor") + (return-type "void") + (params + ((type "int") (name "cursor")))) + + ((name "GetTouchX") + (description "Get touch position X for touch point 0 (relative to screen size)") + (return-type "int")) + + ((name "GetTouchY") + (description "Get touch position Y for touch point 0 (relative to screen size)") + (return-type "int")) + + ((name "GetTouchPosition") + (description "Get touch position XY for a touch point index (relative to screen size)") + (return-type "Vector2") + (params + ((type "int") (name "index")))) + + ((name "GetTouchPointId") + (description "Get touch point identifier for given index") + (return-type "int") + (params + ((type "int") (name "index")))) + + ((name "GetTouchPointCount") + (description "Get number of touch points") + (return-type "int")) + + ((name "SetGesturesEnabled") + (description "Enable a set of gestures using flags") + (return-type "void") + (params + ((type "unsigned int") (name "flags")))) + + ((name "IsGestureDetected") + (description "Check if gesture has been detected") + (return-type "bool") + (params + ((type "unsigned int") (name "gesture")))) + + ((name "GetGestureDetected") + (description "Get latest detected gesture") + (return-type "int")) + + ((name "GetGestureHoldDuration") + (description "Get gesture hold time in seconds") + (return-type "float")) + + ((name "GetGestureDragVector") + (description "Get gesture drag vector") + (return-type "Vector2")) + + ((name "GetGestureDragAngle") + (description "Get gesture drag angle") + (return-type "float")) + + ((name "GetGesturePinchVector") + (description "Get gesture pinch delta") + (return-type "Vector2")) + + ((name "GetGesturePinchAngle") + (description "Get gesture pinch angle") + (return-type "float")) + + ((name "UpdateCamera") + (description "Update camera position for selected mode") + (return-type "void") + (params + ((type "Camera *") (name "camera")) + ((type "int") (name "mode")))) + + ((name "UpdateCameraPro") + (description "Update camera movement/rotation") + (return-type "void") + (params + ((type "Camera *") (name "camera")) + ((type "Vector3") (name "movement")) + ((type "Vector3") (name "rotation")) + ((type "float") (name "zoom")))) + + ((name "SetShapesTexture") + (description "Set texture and rectangle to be used on shapes drawing") + (return-type "void") + (params + ((type "Texture2D") (name "texture")) + ((type "Rectangle") (name "rec")))) + + ((name "GetShapesTexture") + (description "Get texture that is used for shapes drawing") + (return-type "Texture2D")) + + ((name "GetShapesTextureRectangle") + (description "Get texture source rectangle that is used for shapes drawing") + (return-type "Rectangle")) + + ((name "DrawPixel") + (description "Draw a pixel using geometry [Can be slow, use with care]") + (return-type "void") + (params + ((type "int") (name "posX")) + ((type "int") (name "posY")) + ((type "Color") (name "color")))) + + ((name "DrawPixelV") + (description "Draw a pixel using geometry (Vector version) [Can be slow, use with care]") + (return-type "void") + (params + ((type "Vector2") (name "position")) + ((type "Color") (name "color")))) + + ((name "DrawLine") + (description "Draw a line") + (return-type "void") + (params + ((type "int") (name "startPosX")) + ((type "int") (name "startPosY")) + ((type "int") (name "endPosX")) + ((type "int") (name "endPosY")) + ((type "Color") (name "color")))) + + ((name "DrawLineV") + (description "Draw a line (using gl lines)") + (return-type "void") + (params + ((type "Vector2") (name "startPos")) + ((type "Vector2") (name "endPos")) + ((type "Color") (name "color")))) + + ((name "DrawLineEx") + (description "Draw a line (using triangles/quads)") + (return-type "void") + (params + ((type "Vector2") (name "startPos")) + ((type "Vector2") (name "endPos")) + ((type "float") (name "thick")) + ((type "Color") (name "color")))) + + ((name "DrawLineStrip") + (description "Draw lines sequence (using gl lines)") + (return-type "void") + (params + ((type "const Vector2 *") (name "points")) + ((type "int") (name "pointCount")) + ((type "Color") (name "color")))) + + ((name "DrawLineBezier") + (description "Draw line segment cubic-bezier in-out interpolation") + (return-type "void") + (params + ((type "Vector2") (name "startPos")) + ((type "Vector2") (name "endPos")) + ((type "float") (name "thick")) + ((type "Color") (name "color")))) + + ((name "DrawLineDashed") + (description "Draw a dashed line") + (return-type "void") + (params + ((type "Vector2") (name "startPos")) + ((type "Vector2") (name "endPos")) + ((type "int") (name "dashSize")) + ((type "int") (name "spaceSize")) + ((type "Color") (name "color")))) + + ((name "DrawTriangle") + (description "Draw a color-filled triangle, counter-clockwise vertex order") + (return-type "void") + (params + ((type "Vector2") (name "v1")) + ((type "Vector2") (name "v2")) + ((type "Vector2") (name "v3")) + ((type "Color") (name "color")))) + + ((name "DrawTriangleGradient") + (description "Draw triangle with interpolated colors, counter-clockwise vertex/color order") + (return-type "void") + (params + ((type "Vector2") (name "v1")) + ((type "Vector2") (name "v2")) + ((type "Vector2") (name "v3")) + ((type "Color") (name "c1")) + ((type "Color") (name "c2")) + ((type "Color") (name "c3")))) + + ((name "DrawTriangleLines") + (description "Draw triangle outline, counter-clockwise vertex order") + (return-type "void") + (params + ((type "Vector2") (name "v1")) + ((type "Vector2") (name "v2")) + ((type "Vector2") (name "v3")) + ((type "Color") (name "color")))) + + ((name "DrawTriangleFan") + (description "Draw a triangle fan defined by points (first vertex is the center)") + (return-type "void") + (params + ((type "const Vector2 *") (name "points")) + ((type "int") (name "pointCount")) + ((type "Color") (name "color")))) + + ((name "DrawTriangleStrip") + (description "Draw a triangle strip defined by points") + (return-type "void") + (params + ((type "const Vector2 *") (name "points")) + ((type "int") (name "pointCount")) + ((type "Color") (name "color")))) + + ((name "DrawRectangle") + (description "Draw a color-filled rectangle") + (return-type "void") + (params + ((type "int") (name "posX")) + ((type "int") (name "posY")) + ((type "int") (name "width")) + ((type "int") (name "height")) + ((type "Color") (name "color")))) + + ((name "DrawRectangleV") + (description "Draw a color-filled rectangle (Vector version)") + (return-type "void") + (params + ((type "Vector2") (name "position")) + ((type "Vector2") (name "size")) + ((type "Color") (name "color")))) + + ((name "DrawRectangleRec") + (description "Draw a color-filled rectangle") + (return-type "void") + (params + ((type "Rectangle") (name "rec")) + ((type "Color") (name "color")))) + + ((name "DrawRectanglePro") + (description "Draw a color-filled rectangle with pro parameters") + (return-type "void") + (params + ((type "Rectangle") (name "rec")) + ((type "Vector2") (name "origin")) + ((type "float") (name "rotation")) + ((type "Color") (name "color")))) + + ((name "DrawRectangleGradientV") + (description "Draw a vertical-gradient-filled rectangle") + (return-type "void") + (params + ((type "int") (name "posX")) + ((type "int") (name "posY")) + ((type "int") (name "width")) + ((type "int") (name "height")) + ((type "Color") (name "top")) + ((type "Color") (name "bottom")))) + + ((name "DrawRectangleGradientH") + (description "Draw a horizontal-gradient-filled rectangle") + (return-type "void") + (params + ((type "int") (name "posX")) + ((type "int") (name "posY")) + ((type "int") (name "width")) + ((type "int") (name "height")) + ((type "Color") (name "left")) + ((type "Color") (name "right")))) + + ((name "DrawRectangleGradientEx") + (description "Draw a gradient-filled rectangle with custom vertex colors, counter-clockwise color order") + (return-type "void") + (params + ((type "Rectangle") (name "rec")) + ((type "Color") (name "col1")) + ((type "Color") (name "col2")) + ((type "Color") (name "col3")) + ((type "Color") (name "col4")))) + + ((name "DrawRectangleLines") + (description "Draw rectangle outline") + (return-type "void") + (params + ((type "int") (name "posX")) + ((type "int") (name "posY")) + ((type "int") (name "width")) + ((type "int") (name "height")) + ((type "Color") (name "color")))) + + ((name "DrawRectangleLinesEx") + (description "Draw rectangle outline with line thickness") + (return-type "void") + (params + ((type "Rectangle") (name "rec")) + ((type "float") (name "thick")) + ((type "Color") (name "color")))) + + ((name "DrawRectangleRounded") + (description "Draw rectangle with rounded edges") + (return-type "void") + (params + ((type "Rectangle") (name "rec")) + ((type "float") (name "roundness")) + ((type "int") (name "segments")) + ((type "Color") (name "color")))) + + ((name "DrawRectangleRoundedLines") + (description "Draw rectangle lines with rounded edges") + (return-type "void") + (params + ((type "Rectangle") (name "rec")) + ((type "float") (name "roundness")) + ((type "int") (name "segments")) + ((type "Color") (name "color")))) + + ((name "DrawRectangleRoundedLinesEx") + (description "Draw rectangle lines with rounded edges outline and line thickness") + (return-type "void") + (params + ((type "Rectangle") (name "rec")) + ((type "float") (name "roundness")) + ((type "int") (name "segments")) + ((type "float") (name "thick")) + ((type "Color") (name "color")))) + + ((name "DrawPoly") + (description "Draw a polygon of n sides") + (return-type "void") + (params + ((type "Vector2") (name "center")) + ((type "int") (name "sides")) + ((type "float") (name "radius")) + ((type "float") (name "rotation")) + ((type "Color") (name "color")))) + + ((name "DrawPolyLines") + (description "Draw a polygon outline of n sides") + (return-type "void") + (params + ((type "Vector2") (name "center")) + ((type "int") (name "sides")) + ((type "float") (name "radius")) + ((type "float") (name "rotation")) + ((type "Color") (name "color")))) + + ((name "DrawPolyLinesEx") + (description "Draw a polygon outline of n sides with line thickness") + (return-type "void") + (params + ((type "Vector2") (name "center")) + ((type "int") (name "sides")) + ((type "float") (name "radius")) + ((type "float") (name "rotation")) + ((type "float") (name "thick")) + ((type "Color") (name "color")))) + + ((name "DrawCircle") + (description "Draw a color-filled circle") + (return-type "void") + (params + ((type "int") (name "centerX")) + ((type "int") (name "centerY")) + ((type "float") (name "radius")) + ((type "Color") (name "color")))) + + ((name "DrawCircleV") + (description "Draw a color-filled circle (Vector version)") + (return-type "void") + (params + ((type "Vector2") (name "center")) + ((type "float") (name "radius")) + ((type "Color") (name "color")))) + + ((name "DrawCircleGradient") + (description "Draw a gradient-filled circle") + (return-type "void") + (params + ((type "Vector2") (name "center")) + ((type "float") (name "radius")) + ((type "Color") (name "inner")) + ((type "Color") (name "outer")))) + + ((name "DrawCircleSector") + (description "Draw a piece of a circle") + (return-type "void") + (params + ((type "Vector2") (name "center")) + ((type "float") (name "radius")) + ((type "float") (name "startAngle")) + ((type "float") (name "endAngle")) + ((type "int") (name "segments")) + ((type "Color") (name "color")))) + + ((name "DrawCircleSectorLines") + (description "Draw circle sector outline") + (return-type "void") + (params + ((type "Vector2") (name "center")) + ((type "float") (name "radius")) + ((type "float") (name "startAngle")) + ((type "float") (name "endAngle")) + ((type "int") (name "segments")) + ((type "Color") (name "color")))) + + ((name "DrawCircleLines") + (description "Draw circle outline") + (return-type "void") + (params + ((type "int") (name "centerX")) + ((type "int") (name "centerY")) + ((type "float") (name "radius")) + ((type "Color") (name "color")))) + + ((name "DrawCircleLinesV") + (description "Draw circle outline (Vector version)") + (return-type "void") + (params + ((type "Vector2") (name "center")) + ((type "float") (name "radius")) + ((type "Color") (name "color")))) + + ((name "DrawCircleLinesEx") + (description "Draw circle outline with line thickness") + (return-type "void") + (params + ((type "Vector2") (name "center")) + ((type "float") (name "radius")) + ((type "float") (name "thick")) + ((type "Color") (name "color")))) + + ((name "DrawEllipse") + (description "Draw ellipse") + (return-type "void") + (params + ((type "int") (name "centerX")) + ((type "int") (name "centerY")) + ((type "float") (name "radiusH")) + ((type "float") (name "radiusV")) + ((type "Color") (name "color")))) + + ((name "DrawEllipseV") + (description "Draw ellipse (Vector version)") + (return-type "void") + (params + ((type "Vector2") (name "center")) + ((type "float") (name "radiusH")) + ((type "float") (name "radiusV")) + ((type "Color") (name "color")))) + + ((name "DrawEllipseLines") + (description "Draw ellipse outline") + (return-type "void") + (params + ((type "int") (name "centerX")) + ((type "int") (name "centerY")) + ((type "float") (name "radiusH")) + ((type "float") (name "radiusV")) + ((type "Color") (name "color")))) + + ((name "DrawEllipseLinesV") + (description "Draw ellipse outline (Vector version)") + (return-type "void") + (params + ((type "Vector2") (name "center")) + ((type "float") (name "radiusH")) + ((type "float") (name "radiusV")) + ((type "Color") (name "color")))) + + ((name "DrawRing") + (description "Draw ring") + (return-type "void") + (params + ((type "Vector2") (name "center")) + ((type "float") (name "innerRadius")) + ((type "float") (name "outerRadius")) + ((type "float") (name "startAngle")) + ((type "float") (name "endAngle")) + ((type "int") (name "segments")) + ((type "Color") (name "color")))) + + ((name "DrawRingLines") + (description "Draw ring outline") + (return-type "void") + (params + ((type "Vector2") (name "center")) + ((type "float") (name "innerRadius")) + ((type "float") (name "outerRadius")) + ((type "float") (name "startAngle")) + ((type "float") (name "endAngle")) + ((type "int") (name "segments")) + ((type "Color") (name "color")))) + + ((name "DrawSplineLinear") + (description "Draw spline: Linear, minimum 2 points") + (return-type "void") + (params + ((type "const Vector2 *") (name "points")) + ((type "int") (name "pointCount")) + ((type "float") (name "thick")) + ((type "Color") (name "color")))) + + ((name "DrawSplineBasis") + (description "Draw spline: B-Spline, minimum 4 points") + (return-type "void") + (params + ((type "const Vector2 *") (name "points")) + ((type "int") (name "pointCount")) + ((type "float") (name "thick")) + ((type "Color") (name "color")))) + + ((name "DrawSplineCatmullRom") + (description "Draw spline: Catmull-Rom, minimum 4 points") + (return-type "void") + (params + ((type "const Vector2 *") (name "points")) + ((type "int") (name "pointCount")) + ((type "float") (name "thick")) + ((type "Color") (name "color")))) + + ((name "DrawSplineBezierQuadratic") + (description "Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...]") + (return-type "void") + (params + ((type "const Vector2 *") (name "points")) + ((type "int") (name "pointCount")) + ((type "float") (name "thick")) + ((type "Color") (name "color")))) + + ((name "DrawSplineBezierCubic") + (description "Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...]") + (return-type "void") + (params + ((type "const Vector2 *") (name "points")) + ((type "int") (name "pointCount")) + ((type "float") (name "thick")) + ((type "Color") (name "color")))) + + ((name "DrawSplineSegmentLinear") + (description "Draw spline segment: Linear, 2 points") + (return-type "void") + (params + ((type "Vector2") (name "p1")) + ((type "Vector2") (name "p2")) + ((type "float") (name "thick")) + ((type "Color") (name "color")))) + + ((name "DrawSplineSegmentBasis") + (description "Draw spline segment: B-Spline, 4 points") + (return-type "void") + (params + ((type "Vector2") (name "p1")) + ((type "Vector2") (name "p2")) + ((type "Vector2") (name "p3")) + ((type "Vector2") (name "p4")) + ((type "float") (name "thick")) + ((type "Color") (name "color")))) + + ((name "DrawSplineSegmentCatmullRom") + (description "Draw spline segment: Catmull-Rom, 4 points") + (return-type "void") + (params + ((type "Vector2") (name "p1")) + ((type "Vector2") (name "p2")) + ((type "Vector2") (name "p3")) + ((type "Vector2") (name "p4")) + ((type "float") (name "thick")) + ((type "Color") (name "color")))) + + ((name "DrawSplineSegmentBezierQuadratic") + (description "Draw spline segment: Quadratic Bezier, 2 points, 1 control point") + (return-type "void") + (params + ((type "Vector2") (name "p1")) + ((type "Vector2") (name "c2")) + ((type "Vector2") (name "p3")) + ((type "float") (name "thick")) + ((type "Color") (name "color")))) + + ((name "DrawSplineSegmentBezierCubic") + (description "Draw spline segment: Cubic Bezier, 2 points, 2 control points") + (return-type "void") + (params + ((type "Vector2") (name "p1")) + ((type "Vector2") (name "c2")) + ((type "Vector2") (name "c3")) + ((type "Vector2") (name "p4")) + ((type "float") (name "thick")) + ((type "Color") (name "color")))) + + ((name "GetSplinePointLinear") + (description "Get (evaluate) spline point: Linear") + (return-type "Vector2") + (params + ((type "Vector2") (name "startPos")) + ((type "Vector2") (name "endPos")) + ((type "float") (name "t")))) + + ((name "GetSplinePointBasis") + (description "Get (evaluate) spline point: B-Spline") + (return-type "Vector2") + (params + ((type "Vector2") (name "p1")) + ((type "Vector2") (name "p2")) + ((type "Vector2") (name "p3")) + ((type "Vector2") (name "p4")) + ((type "float") (name "t")))) + + ((name "GetSplinePointCatmullRom") + (description "Get (evaluate) spline point: Catmull-Rom") + (return-type "Vector2") + (params + ((type "Vector2") (name "p1")) + ((type "Vector2") (name "p2")) + ((type "Vector2") (name "p3")) + ((type "Vector2") (name "p4")) + ((type "float") (name "t")))) + + ((name "GetSplinePointBezierQuadratic") + (description "Get (evaluate) spline point: Quadratic Bezier") + (return-type "Vector2") + (params + ((type "Vector2") (name "p1")) + ((type "Vector2") (name "c2")) + ((type "Vector2") (name "p3")) + ((type "float") (name "t")))) + + ((name "GetSplinePointBezierCubic") + (description "Get (evaluate) spline point: Cubic Bezier") + (return-type "Vector2") + (params + ((type "Vector2") (name "p1")) + ((type "Vector2") (name "c2")) + ((type "Vector2") (name "c3")) + ((type "Vector2") (name "p4")) + ((type "float") (name "t")))) + + ((name "CheckCollisionRecs") + (description "Check collision between two rectangles") + (return-type "bool") + (params + ((type "Rectangle") (name "rec1")) + ((type "Rectangle") (name "rec2")))) + + ((name "CheckCollisionCircles") + (description "Check collision between two circles") + (return-type "bool") + (params + ((type "Vector2") (name "center1")) + ((type "float") (name "radius1")) + ((type "Vector2") (name "center2")) + ((type "float") (name "radius2")))) + + ((name "CheckCollisionCircleRec") + (description "Check collision between circle and rectangle") + (return-type "bool") + (params + ((type "Vector2") (name "center")) + ((type "float") (name "radius")) + ((type "Rectangle") (name "rec")))) + + ((name "CheckCollisionCircleLine") + (description "Check if circle collides with a line created between two points [p1] and [p2]") + (return-type "bool") + (params + ((type "Vector2") (name "center")) + ((type "float") (name "radius")) + ((type "Vector2") (name "p1")) + ((type "Vector2") (name "p2")))) + + ((name "CheckCollisionPointRec") + (description "Check if point is inside rectangle") + (return-type "bool") + (params + ((type "Vector2") (name "point")) + ((type "Rectangle") (name "rec")))) + + ((name "CheckCollisionPointCircle") + (description "Check if point is inside circle") + (return-type "bool") + (params + ((type "Vector2") (name "point")) + ((type "Vector2") (name "center")) + ((type "float") (name "radius")))) + + ((name "CheckCollisionPointTriangle") + (description "Check if point is inside a triangle") + (return-type "bool") + (params + ((type "Vector2") (name "point")) + ((type "Vector2") (name "p1")) + ((type "Vector2") (name "p2")) + ((type "Vector2") (name "p3")))) + + ((name "CheckCollisionPointLine") + (description "Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold]") + (return-type "bool") + (params + ((type "Vector2") (name "point")) + ((type "Vector2") (name "p1")) + ((type "Vector2") (name "p2")) + ((type "int") (name "threshold")))) + + ((name "CheckCollisionPointPoly") + (description "Check if point is within a polygon described by array of vertices") + (return-type "bool") + (params + ((type "Vector2") (name "point")) + ((type "const Vector2 *") (name "points")) + ((type "int") (name "pointCount")))) + + ((name "CheckCollisionLines") + (description "Check the collision between two lines defined by two points each, returns collision point by reference") + (return-type "bool") + (params + ((type "Vector2") (name "startPos1")) + ((type "Vector2") (name "endPos1")) + ((type "Vector2") (name "startPos2")) + ((type "Vector2") (name "endPos2")) + ((type "Vector2 *") (name "collisionPoint")))) + + ((name "GetCollisionRec") + (description "Get collision rectangle for two rectangles collision") + (return-type "Rectangle") + (params + ((type "Rectangle") (name "rec1")) + ((type "Rectangle") (name "rec2")))) + + ((name "LoadImage") + (description "Load image from file into CPU memory (RAM)") + (return-type "Image") + (params + ((type "const char *") (name "fileName")))) + + ((name "LoadImageRaw") + (description "Load image from RAW file data") + (return-type "Image") + (params + ((type "const char *") (name "fileName")) + ((type "int") (name "width")) + ((type "int") (name "height")) + ((type "int") (name "format")) + ((type "int") (name "headerSize")))) + + ((name "LoadImageAnim") + (description "Load image sequence from file (frames appended to image.data)") + (return-type "Image") + (params + ((type "const char *") (name "fileName")) + ((type "int *") (name "frames")))) + + ((name "LoadImageAnimFromMemory") + (description "Load image sequence from memory buffer") + (return-type "Image") + (params + ((type "const char *") (name "fileType")) + ((type "const unsigned char *") (name "fileData")) + ((type "int") (name "dataSize")) + ((type "int *") (name "frames")))) + + ((name "LoadImageFromMemory") + (description "Load image from memory buffer, fileType refers to extension: i.e. '.png'") + (return-type "Image") + (params + ((type "const char *") (name "fileType")) + ((type "const unsigned char *") (name "fileData")) + ((type "int") (name "dataSize")))) + + ((name "LoadImageFromTexture") + (description "Load image from GPU texture data") + (return-type "Image") + (params + ((type "Texture2D") (name "texture")))) + + ((name "LoadImageFromScreen") + (description "Load image from screen buffer (screenshot)") + (return-type "Image")) + + ((name "IsImageValid") + (description "Check if an image is valid (data and parameters)") + (return-type "bool") + (params + ((type "Image") (name "image")))) + + ((name "UnloadImage") + (description "Unload image from CPU memory (RAM)") + (return-type "void") + (params + ((type "Image") (name "image")))) + + ((name "ExportImage") + (description "Export image data to file, returns true on success") + (return-type "bool") + (params + ((type "Image") (name "image")) + ((type "const char *") (name "fileName")))) + + ((name "ExportImageToMemory") + (description "Export image to memory buffer, memory must be MemFree()") + (return-type "unsigned char *") + (params + ((type "Image") (name "image")) + ((type "const char *") (name "fileType")) + ((type "int *") (name "fileSize")))) + + ((name "ExportImageAsCode") + (description "Export image as code file defining an array of bytes, returns true on success") + (return-type "bool") + (params + ((type "Image") (name "image")) + ((type "const char *") (name "fileName")))) + + ((name "GenImageColor") + (description "Generate image: plain color") + (return-type "Image") + (params + ((type "int") (name "width")) + ((type "int") (name "height")) + ((type "Color") (name "color")))) + + ((name "GenImageGradientLinear") + (description "Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient") + (return-type "Image") + (params + ((type "int") (name "width")) + ((type "int") (name "height")) + ((type "int") (name "direction")) + ((type "Color") (name "start")) + ((type "Color") (name "end")))) + + ((name "GenImageGradientRadial") + (description "Generate image: radial gradient") + (return-type "Image") + (params + ((type "int") (name "width")) + ((type "int") (name "height")) + ((type "float") (name "density")) + ((type "Color") (name "inner")) + ((type "Color") (name "outer")))) + + ((name "GenImageGradientSquare") + (description "Generate image: square gradient") + (return-type "Image") + (params + ((type "int") (name "width")) + ((type "int") (name "height")) + ((type "float") (name "density")) + ((type "Color") (name "inner")) + ((type "Color") (name "outer")))) + + ((name "GenImageChecked") + (description "Generate image: checked") + (return-type "Image") + (params + ((type "int") (name "width")) + ((type "int") (name "height")) + ((type "int") (name "checksX")) + ((type "int") (name "checksY")) + ((type "Color") (name "col1")) + ((type "Color") (name "col2")))) + + ((name "GenImageWhiteNoise") + (description "Generate image: white noise") + (return-type "Image") + (params + ((type "int") (name "width")) + ((type "int") (name "height")) + ((type "float") (name "factor")))) + + ((name "GenImagePerlinNoise") + (description "Generate image: perlin noise") + (return-type "Image") + (params + ((type "int") (name "width")) + ((type "int") (name "height")) + ((type "int") (name "offsetX")) + ((type "int") (name "offsetY")) + ((type "float") (name "scale")))) + + ((name "GenImageCellular") + (description "Generate image: cellular algorithm, bigger tileSize means bigger cells") + (return-type "Image") + (params + ((type "int") (name "width")) + ((type "int") (name "height")) + ((type "int") (name "tileSize")))) + + ((name "GenImageText") + (description "Generate image: grayscale image from text data") + (return-type "Image") + (params + ((type "int") (name "width")) + ((type "int") (name "height")) + ((type "const char *") (name "text")))) + + ((name "ImageCopy") + (description "Create an image duplicate (useful for transformations)") + (return-type "Image") + (params + ((type "Image") (name "image")))) + + ((name "ImageFromImage") + (description "Create an image from another image piece") + (return-type "Image") + (params + ((type "Image") (name "image")) + ((type "Rectangle") (name "rec")))) + + ((name "ImageFromChannel") + (description "Create an image from a selected channel of another image (GRAYSCALE)") + (return-type "Image") + (params + ((type "Image") (name "image")) + ((type "int") (name "selectedChannel")))) + + ((name "ImageText") + (description "Create an image from text (default font)") + (return-type "Image") + (params + ((type "const char *") (name "text")) + ((type "int") (name "fontSize")) + ((type "Color") (name "color")))) + + ((name "ImageTextEx") + (description "Create an image from text (custom sprite font)") + (return-type "Image") + (params + ((type "Font") (name "font")) + ((type "const char *") (name "text")) + ((type "float") (name "fontSize")) + ((type "float") (name "spacing")) + ((type "Color") (name "tint")))) + + ((name "ImageFormat") + (description "Convert image data to desired format") + (return-type "void") + (params + ((type "Image *") (name "image")) + ((type "int") (name "newFormat")))) + + ((name "ImageToPOT") + (description "Convert image to POT (power-of-two)") + (return-type "void") + (params + ((type "Image *") (name "image")) + ((type "Color") (name "fill")))) + + ((name "ImageCrop") + (description "Crop an image to a defined rectangle") + (return-type "void") + (params + ((type "Image *") (name "image")) + ((type "Rectangle") (name "crop")))) + + ((name "ImageAlphaCrop") + (description "Crop image depending on alpha value") + (return-type "void") + (params + ((type "Image *") (name "image")) + ((type "float") (name "threshold")))) + + ((name "ImageAlphaClear") + (description "Clear alpha channel to desired color") + (return-type "void") + (params + ((type "Image *") (name "image")) + ((type "Color") (name "color")) + ((type "float") (name "threshold")))) + + ((name "ImageAlphaMask") + (description "Apply alpha mask to image") + (return-type "void") + (params + ((type "Image *") (name "image")) + ((type "Image") (name "alphaMask")))) + + ((name "ImageAlphaPremultiply") + (description "Premultiply alpha channel") + (return-type "void") + (params + ((type "Image *") (name "image")))) + + ((name "ImageBlurGaussian") + (description "Apply Gaussian blur using a box blur approximation") + (return-type "void") + (params + ((type "Image *") (name "image")) + ((type "int") (name "blurSize")))) + + ((name "ImageKernelConvolution") + (description "Apply custom square convolution kernel to image") + (return-type "void") + (params + ((type "Image *") (name "image")) + ((type "const float *") (name "kernel")) + ((type "int") (name "kernelSize")))) + + ((name "ImageResize") + (description "Resize image (Bicubic scaling algorithm)") + (return-type "void") + (params + ((type "Image *") (name "image")) + ((type "int") (name "newWidth")) + ((type "int") (name "newHeight")))) + + ((name "ImageResizeNN") + (description "Resize image (Nearest-Neighbor scaling algorithm)") + (return-type "void") + (params + ((type "Image *") (name "image")) + ((type "int") (name "newWidth")) + ((type "int") (name "newHeight")))) + + ((name "ImageResizeCanvas") + (description "Resize canvas and fill with color") + (return-type "void") + (params + ((type "Image *") (name "image")) + ((type "int") (name "newWidth")) + ((type "int") (name "newHeight")) + ((type "int") (name "offsetX")) + ((type "int") (name "offsetY")) + ((type "Color") (name "fill")))) + + ((name "ImageMipmaps") + (description "Compute all mipmap levels for a provided image") + (return-type "void") + (params + ((type "Image *") (name "image")))) + + ((name "ImageDither") + (description "Dither image data to 16bpp or lower (Floyd-Steinberg dithering)") + (return-type "void") + (params + ((type "Image *") (name "image")) + ((type "int") (name "rBpp")) + ((type "int") (name "gBpp")) + ((type "int") (name "bBpp")) + ((type "int") (name "aBpp")))) + + ((name "ImageFlipVertical") + (description "Flip image vertically") + (return-type "void") + (params + ((type "Image *") (name "image")))) + + ((name "ImageFlipHorizontal") + (description "Flip image horizontally") + (return-type "void") + (params + ((type "Image *") (name "image")))) + + ((name "ImageRotate") + (description "Rotate image by input angle in degrees (-359 to 359)") + (return-type "void") + (params + ((type "Image *") (name "image")) + ((type "int") (name "degrees")))) + + ((name "ImageRotateCW") + (description "Rotate image clockwise 90deg") + (return-type "void") + (params + ((type "Image *") (name "image")))) + + ((name "ImageRotateCCW") + (description "Rotate image counter-clockwise 90deg") + (return-type "void") + (params + ((type "Image *") (name "image")))) + + ((name "ImageColorTint") + (description "Modify image color: tint") + (return-type "void") + (params + ((type "Image *") (name "image")) + ((type "Color") (name "color")))) + + ((name "ImageColorInvert") + (description "Modify image color: invert") + (return-type "void") + (params + ((type "Image *") (name "image")))) + + ((name "ImageColorGrayscale") + (description "Modify image color: grayscale") + (return-type "void") + (params + ((type "Image *") (name "image")))) + + ((name "ImageColorContrast") + (description "Modify image color: contrast (-100 to 100)") + (return-type "void") + (params + ((type "Image *") (name "image")) + ((type "int") (name "contrast")))) + + ((name "ImageColorBrightness") + (description "Modify image color: brightness (-255 to 255)") + (return-type "void") + (params + ((type "Image *") (name "image")) + ((type "int") (name "brightness")))) + + ((name "ImageColorReplace") + (description "Modify image color: replace color") + (return-type "void") + (params + ((type "Image *") (name "image")) + ((type "Color") (name "color")) + ((type "Color") (name "replace")))) + + ((name "LoadImageColors") + (description "Load color data from image as a Color array (RGBA - 32bit)") + (return-type "Color *") + (params + ((type "Image") (name "image")))) + + ((name "LoadImagePalette") + (description "Load colors palette from image as a Color array (RGBA - 32bit)") + (return-type "Color *") + (params + ((type "Image") (name "image")) + ((type "int") (name "maxPaletteSize")) + ((type "int *") (name "colorCount")))) + + ((name "UnloadImageColors") + (description "Unload color data loaded with LoadImageColors()") + (return-type "void") + (params + ((type "Color *") (name "colors")))) + + ((name "UnloadImagePalette") + (description "Unload colors palette loaded with LoadImagePalette()") + (return-type "void") + (params + ((type "Color *") (name "colors")))) + + ((name "GetImageAlphaBorder") + (description "Get image alpha border rectangle") + (return-type "Rectangle") + (params + ((type "Image") (name "image")) + ((type "float") (name "threshold")))) + + ((name "GetImageColor") + (description "Get image pixel color at (x, y) position") + (return-type "Color") + (params + ((type "Image") (name "image")) + ((type "int") (name "x")) + ((type "int") (name "y")))) + + ((name "ImageClearBackground") + (description "Clear image background with given color") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "Color") (name "color")))) + + ((name "ImageDrawPixel") + (description "Draw pixel within an image") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "int") (name "posX")) + ((type "int") (name "posY")) + ((type "Color") (name "color")))) + + ((name "ImageDrawPixelV") + (description "Draw pixel within an image (Vector version)") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "Vector2") (name "position")) + ((type "Color") (name "color")))) + + ((name "ImageDrawLine") + (description "Draw line within an image") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "int") (name "startPosX")) + ((type "int") (name "startPosY")) + ((type "int") (name "endPosX")) + ((type "int") (name "endPosY")) + ((type "Color") (name "color")))) + + ((name "ImageDrawLineV") + (description "Draw line within an image (Vector version)") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "Vector2") (name "start")) + ((type "Vector2") (name "end")) + ((type "Color") (name "color")))) + + ((name "ImageDrawLineEx") + (description "Draw a line defining thickness within an image") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "Vector2") (name "start")) + ((type "Vector2") (name "end")) + ((type "int") (name "thick")) + ((type "Color") (name "color")))) + + ((name "ImageDrawLineStrip") + (description "Draw a lines sequence within an image") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "const Vector2 *") (name "points")) + ((type "int") (name "pointCount")) + ((type "Color") (name "color")))) + + ((name "ImageDrawTriangle") + (description "Draw triangle within an image") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "Vector2") (name "v1")) + ((type "Vector2") (name "v2")) + ((type "Vector2") (name "v3")) + ((type "Color") (name "color")))) + + ((name "ImageDrawTriangleGradient") + (description "Draw triangle with interpolated colors within an image") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "Vector2") (name "v1")) + ((type "Vector2") (name "v2")) + ((type "Vector2") (name "v3")) + ((type "Color") (name "c1")) + ((type "Color") (name "c2")) + ((type "Color") (name "c3")))) + + ((name "ImageDrawTriangleLines") + (description "Draw triangle outline within an image") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "Vector2") (name "v1")) + ((type "Vector2") (name "v2")) + ((type "Vector2") (name "v3")) + ((type "Color") (name "color")))) + + ((name "ImageDrawTriangleFan") + (description "Draw a triangle fan defined by points within an image (first vertex is the center)") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "const Vector2 *") (name "points")) + ((type "int") (name "pointCount")) + ((type "Color") (name "color")))) + + ((name "ImageDrawTriangleStrip") + (description "Draw a triangle strip defined by points within an image") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "const Vector2 *") (name "points")) + ((type "int") (name "pointCount")) + ((type "Color") (name "color")))) + + ((name "ImageDrawRectangle") + (description "Draw rectangle within an image") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "int") (name "posX")) + ((type "int") (name "posY")) + ((type "int") (name "width")) + ((type "int") (name "height")) + ((type "Color") (name "color")))) + + ((name "ImageDrawRectangleV") + (description "Draw rectangle within an image (Vector version)") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "Vector2") (name "position")) + ((type "Vector2") (name "size")) + ((type "Color") (name "color")))) + + ((name "ImageDrawRectangleRec") + (description "Draw rectangle within an image") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "Rectangle") (name "rec")) + ((type "Color") (name "color")))) + + ((name "ImageDrawRectanglePro") + (description "Draw a color-filled rectangle with pro parameters within and image") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "Rectangle") (name "rec")) + ((type "Vector2") (name "origin")) + ((type "float") (name "rotation")) + ((type "Color") (name "color")))) + + ((name "ImageDrawRectangleLines") + (description "Draw rectangle lines within an image") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "int") (name "posX")) + ((type "int") (name "posY")) + ((type "int") (name "width")) + ((type "int") (name "height")) + ((type "Color") (name "color")))) + + ((name "ImageDrawRectangleLinesEx") + (description "Draw rectangle lines within an image with line thickness") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "Rectangle") (name "rec")) + ((type "int") (name "thick")) + ((type "Color") (name "color")))) + + ((name "ImageDrawRectangleGradientEx") + (description "Draw rectangle with gradient colors within an image, counter-clockwise color order") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "Rectangle") (name "rec")) + ((type "Color") (name "col1")) + ((type "Color") (name "col2")) + ((type "Color") (name "col3")) + ((type "Color") (name "col4")))) + + ((name "ImageDrawCircle") + (description "Draw a filled circle within an image") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "int") (name "centerX")) + ((type "int") (name "centerY")) + ((type "int") (name "radius")) + ((type "Color") (name "color")))) + + ((name "ImageDrawCircleV") + (description "Draw a filled circle within an image (Vector version)") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "Vector2") (name "center")) + ((type "int") (name "radius")) + ((type "Color") (name "color")))) + + ((name "ImageDrawCircleLines") + (description "Draw circle outline within an image") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "int") (name "centerX")) + ((type "int") (name "centerY")) + ((type "int") (name "radius")) + ((type "Color") (name "color")))) + + ((name "ImageDrawCircleLinesV") + (description "Draw circle outline within an image (Vector version)") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "Vector2") (name "center")) + ((type "int") (name "radius")) + ((type "Color") (name "color")))) + + ((name "ImageDrawCircleGradient") + (description "Draw a gradient-filled circle within an image") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "Vector2") (name "center")) + ((type "float") (name "radius")) + ((type "Color") (name "inner")) + ((type "Color") (name "outer")))) + + ((name "ImageDrawImage") + (description "Draw an image within an image") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "Image") (name "src")) + ((type "int") (name "posX")) + ((type "int") (name "posY")) + ((type "Color") (name "tint")))) + + ((name "ImageDrawImageEx") + (description "Draw an image with scaling and rotation within an image") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "Image") (name "src")) + ((type "Vector2") (name "position")) + ((type "float") (name "rotation")) + ((type "float") (name "scale")) + ((type "Color") (name "tint")))) + + ((name "ImageDrawImageRec") + (description "Draw a part of an image defined by a rectangle within an image") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "Image") (name "src")) + ((type "Rectangle") (name "srcRec")) + ((type "Vector2") (name "position")) + ((type "Color") (name "tint")))) + + ((name "ImageDrawImagePro") + (description "Draw a part of an image defined by a rectangle into destination rectangle, with scaling and rotation, within an image") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "Image") (name "src")) + ((type "Rectangle") (name "srcRec")) + ((type "Rectangle") (name "dstRec")) + ((type "Vector2") (name "origin")) + ((type "float") (name "rotation")) + ((type "Color") (name "tint")))) + + ((name "ImageDrawText") + (description "Draw text (using default font) within an image (destination)") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "const char *") (name "text")) + ((type "int") (name "posX")) + ((type "int") (name "posY")) + ((type "int") (name "fontSize")) + ((type "Color") (name "color")))) + + ((name "ImageDrawTextEx") + (description "Draw text (custom sprite font) within an image (destination)") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "Font") (name "font")) + ((type "const char *") (name "text")) + ((type "Vector2") (name "position")) + ((type "float") (name "fontSize")) + ((type "float") (name "spacing")) + ((type "Color") (name "tint")))) + + ((name "ImageDrawTextPro") + (description "Draw text using Font and pro parameters (rotation)") + (return-type "void") + (params + ((type "Image *") (name "dst")) + ((type "Font") (name "font")) + ((type "const char *") (name "text")) + ((type "Vector2") (name "position")) + ((type "Vector2") (name "origin")) + ((type "float") (name "rotation")) + ((type "float") (name "fontSize")) + ((type "float") (name "spacing")) + ((type "Color") (name "tint")))) + + ((name "LoadTexture") + (description "Load texture from file into GPU memory (VRAM)") + (return-type "Texture2D") + (params + ((type "const char *") (name "fileName")))) + + ((name "LoadTextureFromImage") + (description "Load texture from image data") + (return-type "Texture2D") + (params + ((type "Image") (name "image")))) + + ((name "LoadTextureCubemap") + (description "Load cubemap from image, multiple image cubemap layouts supported") + (return-type "TextureCubemap") + (params + ((type "Image") (name "image")) + ((type "int") (name "layout")))) + + ((name "LoadRenderTexture") + (description "Load texture for rendering (framebuffer)") + (return-type "RenderTexture2D") + (params + ((type "int") (name "width")) + ((type "int") (name "height")))) + + ((name "IsTextureValid") + (description "Check if texture is valid (loaded in GPU)") + (return-type "bool") + (params + ((type "Texture2D") (name "texture")))) + + ((name "UnloadTexture") + (description "Unload texture from GPU memory (VRAM)") + (return-type "void") + (params + ((type "Texture2D") (name "texture")))) + + ((name "IsRenderTextureValid") + (description "Check if render texture is valid (loaded in GPU)") + (return-type "bool") + (params + ((type "RenderTexture2D") (name "target")))) + + ((name "UnloadRenderTexture") + (description "Unload render texture from GPU memory (VRAM)") + (return-type "void") + (params + ((type "RenderTexture2D") (name "target")))) + + ((name "UpdateTexture") + (description "Update GPU texture with new data (pixels should be able to fill texture)") + (return-type "void") + (params + ((type "Texture2D") (name "texture")) + ((type "const void *") (name "pixels")))) + + ((name "UpdateTextureRec") + (description "Update GPU texture rectangle with new data (pixels and rec should fit in texture)") + (return-type "void") + (params + ((type "Texture2D") (name "texture")) + ((type "Rectangle") (name "rec")) + ((type "const void *") (name "pixels")))) + + ((name "GenTextureMipmaps") + (description "Generate GPU mipmaps for a texture") + (return-type "void") + (params + ((type "Texture2D *") (name "texture")))) + + ((name "SetTextureFilter") + (description "Set texture scaling filter mode") + (return-type "void") + (params + ((type "Texture2D") (name "texture")) + ((type "int") (name "filter")))) + + ((name "SetTextureWrap") + (description "Set texture wrapping mode") + (return-type "void") + (params + ((type "Texture2D") (name "texture")) + ((type "int") (name "wrap")))) + + ((name "DrawTexture") + (description "Draw a Texture2D") + (return-type "void") + (params + ((type "Texture2D") (name "texture")) + ((type "int") (name "posX")) + ((type "int") (name "posY")) + ((type "Color") (name "tint")))) + + ((name "DrawTextureV") + (description "Draw a Texture2D with position defined as Vector2") + (return-type "void") + (params + ((type "Texture2D") (name "texture")) + ((type "Vector2") (name "position")) + ((type "Color") (name "tint")))) + + ((name "DrawTextureEx") + (description "Draw a Texture2D with rotation and scale") + (return-type "void") + (params + ((type "Texture2D") (name "texture")) + ((type "Vector2") (name "position")) + ((type "float") (name "rotation")) + ((type "float") (name "scale")) + ((type "Color") (name "tint")))) + + ((name "DrawTextureRec") + (description "Draw a part of a texture defined by a rectangle") + (return-type "void") + (params + ((type "Texture2D") (name "texture")) + ((type "Rectangle") (name "rec")) + ((type "Vector2") (name "position")) + ((type "Color") (name "tint")))) + + ((name "DrawTexturePro") + (description "Draw a part of a texture defined by a source rectangle to destination rectangle, with scaling and rotation") + (return-type "void") + (params + ((type "Texture2D") (name "texture")) + ((type "Rectangle") (name "srcrec")) + ((type "Rectangle") (name "dstrec")) + ((type "Vector2") (name "origin")) + ((type "float") (name "rotation")) + ((type "Color") (name "tint")))) + + ((name "DrawTextureNPatch") + (description "Draw a texture (or part of it) that stretches or shrinks nicely") + (return-type "void") + (params + ((type "Texture2D") (name "texture")) + ((type "NPatchInfo") (name "nPatchInfo")) + ((type "Rectangle") (name "dstrec")) + ((type "Vector2") (name "origin")) + ((type "float") (name "rotation")) + ((type "Color") (name "tint")))) + + ((name "ColorIsEqual") + (description "Check if two colors are equal") + (return-type "bool") + (params + ((type "Color") (name "col1")) + ((type "Color") (name "col2")))) + + ((name "Fade") + (description "Get color with alpha applied, alpha goes from 0.0f to 1.0f") + (return-type "Color") + (params + ((type "Color") (name "color")) + ((type "float") (name "alpha")))) + + ((name "ColorToInt") + (description "Get hexadecimal value for a Color (0xRRGGBBAA)") + (return-type "int") + (params + ((type "Color") (name "color")))) + + ((name "ColorNormalize") + (description "Get Color normalized as float [0..1]") + (return-type "Vector4") + (params + ((type "Color") (name "color")))) + + ((name "ColorFromNormalized") + (description "Get Color from normalized values [0..1]") + (return-type "Color") + (params + ((type "Vector4") (name "normalized")))) + + ((name "ColorToHSV") + (description "Get HSV values for a Color, hue [0..360], saturation/value [0..1]") + (return-type "Vector3") + (params + ((type "Color") (name "color")))) + + ((name "ColorFromHSV") + (description "Get a Color from HSV values, hue [0..360], saturation/value [0..1]") + (return-type "Color") + (params + ((type "float") (name "hue")) + ((type "float") (name "saturation")) + ((type "float") (name "value")))) + + ((name "ColorTint") + (description "Get color multiplied with another color") + (return-type "Color") + (params + ((type "Color") (name "color")) + ((type "Color") (name "tint")))) + + ((name "ColorBrightness") + (description "Get color with brightness correction, brightness factor goes from -1.0f to 1.0f") + (return-type "Color") + (params + ((type "Color") (name "color")) + ((type "float") (name "factor")))) + + ((name "ColorContrast") + (description "Get color with contrast correction, contrast values between -1.0f and 1.0f") + (return-type "Color") + (params + ((type "Color") (name "color")) + ((type "float") (name "contrast")))) + + ((name "ColorAlpha") + (description "Get color with alpha applied, alpha goes from 0.0f to 1.0f") + (return-type "Color") + (params + ((type "Color") (name "color")) + ((type "float") (name "alpha")))) + + ((name "ColorAlphaBlend") + (description "Get src alpha-blended into dst color with tint") + (return-type "Color") + (params + ((type "Color") (name "dst")) + ((type "Color") (name "src")) + ((type "Color") (name "tint")))) + + ((name "ColorLerp") + (description "Get color lerp interpolation between two colors, factor [0.0f..1.0f]") + (return-type "Color") + (params + ((type "Color") (name "color1")) + ((type "Color") (name "color2")) + ((type "float") (name "factor")))) + + ((name "GetColor") + (description "Get Color structure from hexadecimal value") + (return-type "Color") + (params + ((type "unsigned int") (name "hexValue")))) + + ((name "GetPixelColor") + (description "Get Color from a source pixel pointer of certain format") + (return-type "Color") + (params + ((type "const void *") (name "srcPtr")) + ((type "int") (name "format")))) + + ((name "SetPixelColor") + (description "Set color formatted into destination pixel pointer") + (return-type "void") + (params + ((type "void *") (name "dstPtr")) + ((type "Color") (name "color")) + ((type "int") (name "format")))) + + ((name "GetPixelDataSize") + (description "Get pixel data size in bytes for certain format") + (return-type "int") + (params + ((type "int") (name "width")) + ((type "int") (name "height")) + ((type "int") (name "format")))) + + ((name "GetFontDefault") + (description "Get the default Font") + (return-type "Font")) + + ((name "LoadFont") + (description "Load font from file into GPU memory (VRAM)") + (return-type "Font") + (params + ((type "const char *") (name "fileName")))) + + ((name "LoadFontEx") + (description "Load font from file with defined codepoints and generation size, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height") + (return-type "Font") + (params + ((type "const char *") (name "fileName")) + ((type "int") (name "fontSize")) + ((type "const int *") (name "codepoints")) + ((type "int") (name "codepointCount")))) + + ((name "LoadFontFromImage") + (description "Load font from Image (XNA style)") + (return-type "Font") + (params + ((type "Image") (name "image")) + ((type "Color") (name "key")) + ((type "int") (name "firstChar")))) + + ((name "LoadFontFromMemory") + (description "Load font from memory buffer, fileType refers to extension: i.e. '.ttf'") + (return-type "Font") + (params + ((type "const char *") (name "fileType")) + ((type "const unsigned char *") (name "fileData")) + ((type "int") (name "dataSize")) + ((type "int") (name "fontSize")) + ((type "const int *") (name "codepoints")) + ((type "int") (name "codepointCount")))) + + ((name "IsFontValid") + (description "Check if font is valid (font data loaded, WARNING: GPU texture not checked)") + (return-type "bool") + (params + ((type "Font") (name "font")))) + + ((name "LoadFontData") + (description "Load font data for further use") + (return-type "GlyphInfo *") + (params + ((type "const unsigned char *") (name "fileData")) + ((type "int") (name "dataSize")) + ((type "int") (name "fontSize")) + ((type "const int *") (name "codepoints")) + ((type "int") (name "codepointCount")) + ((type "int") (name "type")) + ((type "int *") (name "glyphCount")))) + + ((name "GenImageFontAtlas") + (description "Generate image font atlas using chars info") + (return-type "Image") + (params + ((type "const GlyphInfo *") (name "glyphs")) + ((type "Rectangle **") (name "glyphRecs")) + ((type "int") (name "glyphCount")) + ((type "int") (name "fontSize")) + ((type "int") (name "padding")) + ((type "int") (name "packMethod")))) + + ((name "UnloadFontData") + (description "Unload font chars info data (RAM)") + (return-type "void") + (params + ((type "GlyphInfo *") (name "glyphs")) + ((type "int") (name "glyphCount")))) + + ((name "UnloadFont") + (description "Unload font from GPU memory (VRAM)") + (return-type "void") + (params + ((type "Font") (name "font")))) + + ((name "ExportFontAsCode") + (description "Export font as code file, returns true on success") + (return-type "bool") + (params + ((type "Font") (name "font")) + ((type "const char *") (name "fileName")))) + + ((name "DrawFPS") + (description "Draw current FPS") + (return-type "void") + (params + ((type "int") (name "posX")) + ((type "int") (name "posY")))) + + ((name "DrawText") + (description "Draw text (using default font)") + (return-type "void") + (params + ((type "const char *") (name "text")) + ((type "int") (name "posX")) + ((type "int") (name "posY")) + ((type "int") (name "fontSize")) + ((type "Color") (name "color")))) + + ((name "DrawTextEx") + (description "Draw text using font and additional parameters") + (return-type "void") + (params + ((type "Font") (name "font")) + ((type "const char *") (name "text")) + ((type "Vector2") (name "position")) + ((type "float") (name "fontSize")) + ((type "float") (name "spacing")) + ((type "Color") (name "tint")))) + + ((name "DrawTextPro") + (description "Draw text using Font and pro parameters (rotation)") + (return-type "void") + (params + ((type "Font") (name "font")) + ((type "const char *") (name "text")) + ((type "Vector2") (name "position")) + ((type "Vector2") (name "origin")) + ((type "float") (name "rotation")) + ((type "float") (name "fontSize")) + ((type "float") (name "spacing")) + ((type "Color") (name "tint")))) + + ((name "DrawTextCodepoint") + (description "Draw one character (codepoint)") + (return-type "void") + (params + ((type "Font") (name "font")) + ((type "int") (name "codepoint")) + ((type "Vector2") (name "position")) + ((type "float") (name "fontSize")) + ((type "Color") (name "tint")))) + + ((name "DrawTextCodepoints") + (description "Draw multiple characters (codepoint)") + (return-type "void") + (params + ((type "Font") (name "font")) + ((type "const int *") (name "codepoints")) + ((type "int") (name "codepointCount")) + ((type "Vector2") (name "position")) + ((type "float") (name "fontSize")) + ((type "float") (name "spacing")) + ((type "Color") (name "tint")))) + + ((name "SetTextLineSpacing") + (description "Set vertical line spacing when drawing with line-breaks") + (return-type "void") + (params + ((type "int") (name "spacing")))) + + ((name "MeasureText") + (description "Measure string width for default font") + (return-type "int") + (params + ((type "const char *") (name "text")) + ((type "int") (name "fontSize")))) + + ((name "MeasureTextEx") + (description "Measure string size for Font") + (return-type "Vector2") + (params + ((type "Font") (name "font")) + ((type "const char *") (name "text")) + ((type "float") (name "fontSize")) + ((type "float") (name "spacing")))) + + ((name "MeasureTextCodepoints") + (description "Measure string size for an existing array of codepoints for Font") + (return-type "Vector2") + (params + ((type "Font") (name "font")) + ((type "const int *") (name "codepoints")) + ((type "int") (name "length")) + ((type "float") (name "fontSize")) + ((type "float") (name "spacing")))) + + ((name "GetGlyphIndex") + (description "Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found") + (return-type "int") + (params + ((type "Font") (name "font")) + ((type "int") (name "codepoint")))) + + ((name "GetGlyphInfo") + (description "Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found") + (return-type "GlyphInfo") + (params + ((type "Font") (name "font")) + ((type "int") (name "codepoint")))) + + ((name "GetGlyphAtlasRec") + (description "Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found") + (return-type "Rectangle") + (params + ((type "Font") (name "font")) + ((type "int") (name "codepoint")))) + + ((name "LoadUTF8") + (description "Load UTF-8 text encoded from codepoints array") + (return-type "char *") + (params + ((type "const int *") (name "codepoints")) + ((type "int") (name "length")))) + + ((name "UnloadUTF8") + (description "Unload UTF-8 text encoded from codepoints array") + (return-type "void") + (params + ((type "char *") (name "text")))) + + ((name "LoadCodepoints") + (description "Load all codepoints from a UTF-8 text string, codepoints count returned by parameter") + (return-type "int *") + (params + ((type "const char *") (name "text")) + ((type "int *") (name "count")))) + + ((name "UnloadCodepoints") + (description "Unload codepoints data from memory") + (return-type "void") + (params + ((type "int *") (name "codepoints")))) + + ((name "GetCodepointCount") + (description "Get total number of codepoints in a UTF-8 encoded string") + (return-type "int") + (params + ((type "const char *") (name "text")))) + + ((name "GetCodepoint") + (description "Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure") + (return-type "int") + (params + ((type "const char *") (name "text")) + ((type "int *") (name "codepointSize")))) + + ((name "GetCodepointNext") + (description "Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure") + (return-type "int") + (params + ((type "const char *") (name "text")) + ((type "int *") (name "codepointSize")))) + + ((name "GetCodepointPrevious") + (description "Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure") + (return-type "int") + (params + ((type "const char *") (name "text")) + ((type "int *") (name "codepointSize")))) + + ((name "CodepointToUTF8") + (description "Encode one codepoint into UTF-8 byte array (array length returned as parameter)") + (return-type "const char *") + (params + ((type "int") (name "codepoint")) + ((type "int *") (name "utf8Size")))) + + ((name "LoadTextLines") + (description "Load text as separate lines ('\\n')") + (return-type "char **") + (params + ((type "const char *") (name "text")) + ((type "int *") (name "count")))) + + ((name "UnloadTextLines") + (description "Unload text lines") + (return-type "void") + (params + ((type "char **") (name "text")) + ((type "int") (name "lineCount")))) + + ((name "TextCopy") + (description "Copy one string to another, returns bytes copied") + (return-type "int") + (params + ((type "char *") (name "dst")) + ((type "const char *") (name "src")))) + + ((name "TextIsEqual") + (description "Check if two text strings are equal") + (return-type "bool") + (params + ((type "const char *") (name "text1")) + ((type "const char *") (name "text2")))) + + ((name "TextLength") + (description "Get text length, checks for '\\0' ending") + (return-type "unsigned int") + (params + ((type "const char *") (name "text")))) + + ((name "TextFormat") + (description "Text formatting with variables (sprintf() style)") + (return-type "const char *") + (params + ((type "const char *") (name "text")) + ((type "...") (name "args")))) + + ((name "TextSubtext") + (description "Get a piece of a text string") + (return-type "const char *") + (params + ((type "const char *") (name "text")) + ((type "int") (name "position")) + ((type "int") (name "length")))) + + ((name "TextRemoveSpaces") + (description "Remove text spaces, concat words") + (return-type "const char *") + (params + ((type "const char *") (name "text")))) + + ((name "GetTextBetween") + (description "Get text between two strings") + (return-type "char *") + (params + ((type "const char *") (name "text")) + ((type "const char *") (name "begin")) + ((type "const char *") (name "end")))) + + ((name "TextReplace") + (description "Replace text string with new string") + (return-type "char *") + (params + ((type "const char *") (name "text")) + ((type "const char *") (name "search")) + ((type "const char *") (name "replacement")))) + + ((name "TextReplaceAlloc") + (description "Replace text string with new string, memory must be MemFree()") + (return-type "char *") + (params + ((type "const char *") (name "text")) + ((type "const char *") (name "search")) + ((type "const char *") (name "replacement")))) + + ((name "TextReplaceBetween") + (description "Replace text between two specific strings") + (return-type "char *") + (params + ((type "const char *") (name "text")) + ((type "const char *") (name "begin")) + ((type "const char *") (name "end")) + ((type "const char *") (name "replacement")))) + + ((name "TextReplaceBetweenAlloc") + (description "Replace text between two specific strings, memory must be MemFree()") + (return-type "char *") + (params + ((type "const char *") (name "text")) + ((type "const char *") (name "begin")) + ((type "const char *") (name "end")) + ((type "const char *") (name "replacement")))) + + ((name "TextInsert") + (description "Insert text in a defined byte position") + (return-type "char *") + (params + ((type "const char *") (name "text")) + ((type "const char *") (name "insert")) + ((type "int") (name "position")))) + + ((name "TextInsertAlloc") + (description "Insert text in a defined byte position, memory must be MemFree()") + (return-type "char *") + (params + ((type "const char *") (name "text")) + ((type "const char *") (name "insert")) + ((type "int") (name "position")))) + + ((name "TextJoin") + (description "Join text strings with delimiter") + (return-type "char *") + (params + ((type "char **") (name "textList")) + ((type "int") (name "count")) + ((type "const char *") (name "delimiter")))) + + ((name "TextSplit") + (description "Split text into multiple strings, using MAX_TEXTSPLIT_COUNT static strings") + (return-type "char **") + (params + ((type "const char *") (name "text")) + ((type "char") (name "delimiter")) + ((type "int *") (name "count")))) + + ((name "TextAppend") + (description "Append text at specific position and move cursor") + (return-type "void") + (params + ((type "char *") (name "text")) + ((type "const char *") (name "append")) + ((type "int *") (name "position")))) + + ((name "TextFindIndex") + (description "Find first text occurrence within a string, -1 if not found") + (return-type "int") + (params + ((type "const char *") (name "text")) + ((type "const char *") (name "search")))) + + ((name "TextToUpper") + (description "Get upper case version of provided string") + (return-type "char *") + (params + ((type "const char *") (name "text")))) + + ((name "TextToLower") + (description "Get lower case version of provided string") + (return-type "char *") + (params + ((type "const char *") (name "text")))) + + ((name "TextToPascal") + (description "Get Pascal case notation version of provided string") + (return-type "char *") + (params + ((type "const char *") (name "text")))) + + ((name "TextToSnake") + (description "Get Snake case notation version of provided string") + (return-type "char *") + (params + ((type "const char *") (name "text")))) + + ((name "TextToCamel") + (description "Get Camel case notation version of provided string") + (return-type "char *") + (params + ((type "const char *") (name "text")))) + + ((name "TextToInteger") + (description "Get integer value from text") + (return-type "int") + (params + ((type "const char *") (name "text")))) + + ((name "TextToFloat") + (description "Get float value from text") + (return-type "float") + (params + ((type "const char *") (name "text")))) + + ((name "DrawLine3D") + (description "Draw a line in 3D world space") + (return-type "void") + (params + ((type "Vector3") (name "startPos")) + ((type "Vector3") (name "endPos")) + ((type "Color") (name "color")))) + + ((name "DrawPoint3D") + (description "Draw a point in 3D space, actually a small line") + (return-type "void") + (params + ((type "Vector3") (name "position")) + ((type "Color") (name "color")))) + + ((name "DrawCircle3D") + (description "Draw a circle in 3D world space") + (return-type "void") + (params + ((type "Vector3") (name "center")) + ((type "float") (name "radius")) + ((type "Vector3") (name "rotationAxis")) + ((type "float") (name "rotationAngle")) + ((type "Color") (name "color")))) + + ((name "DrawTriangle3D") + (description "Draw a color-filled triangle, counter-clockwise vertex order") + (return-type "void") + (params + ((type "Vector3") (name "v1")) + ((type "Vector3") (name "v2")) + ((type "Vector3") (name "v3")) + ((type "Color") (name "color")))) + + ((name "DrawTriangleStrip3D") + (description "Draw a triangle strip defined by points") + (return-type "void") + (params + ((type "const Vector3 *") (name "points")) + ((type "int") (name "pointCount")) + ((type "Color") (name "color")))) + + ((name "DrawCube") + (description "Draw cube") + (return-type "void") + (params + ((type "Vector3") (name "position")) + ((type "float") (name "width")) + ((type "float") (name "height")) + ((type "float") (name "length")) + ((type "Color") (name "color")))) + + ((name "DrawCubeV") + (description "Draw cube (Vector version)") + (return-type "void") + (params + ((type "Vector3") (name "position")) + ((type "Vector3") (name "size")) + ((type "Color") (name "color")))) + + ((name "DrawCubeWires") + (description "Draw cube wires") + (return-type "void") + (params + ((type "Vector3") (name "position")) + ((type "float") (name "width")) + ((type "float") (name "height")) + ((type "float") (name "length")) + ((type "Color") (name "color")))) + + ((name "DrawCubeWiresV") + (description "Draw cube wires (Vector version)") + (return-type "void") + (params + ((type "Vector3") (name "position")) + ((type "Vector3") (name "size")) + ((type "Color") (name "color")))) + + ((name "DrawSphere") + (description "Draw sphere") + (return-type "void") + (params + ((type "Vector3") (name "centerPos")) + ((type "float") (name "radius")) + ((type "Color") (name "color")))) + + ((name "DrawSphereEx") + (description "Draw sphere with defined rings and slices") + (return-type "void") + (params + ((type "Vector3") (name "centerPos")) + ((type "float") (name "radius")) + ((type "int") (name "rings")) + ((type "int") (name "slices")) + ((type "Color") (name "color")))) + + ((name "DrawSphereWires") + (description "Draw sphere wires") + (return-type "void") + (params + ((type "Vector3") (name "centerPos")) + ((type "float") (name "radius")) + ((type "int") (name "rings")) + ((type "int") (name "slices")) + ((type "Color") (name "color")))) + + ((name "DrawCylinder") + (description "Draw a cylinder/cone") + (return-type "void") + (params + ((type "Vector3") (name "position")) + ((type "float") (name "radiusTop")) + ((type "float") (name "radiusBottom")) + ((type "float") (name "height")) + ((type "int") (name "sides")) + ((type "Color") (name "color")))) + + ((name "DrawCylinderEx") + (description "Draw a cylinder with base at startPos and top at endPos") + (return-type "void") + (params + ((type "Vector3") (name "startPos")) + ((type "Vector3") (name "endPos")) + ((type "float") (name "startRadius")) + ((type "float") (name "endRadius")) + ((type "int") (name "sides")) + ((type "Color") (name "color")))) + + ((name "DrawCylinderWires") + (description "Draw a cylinder/cone wires") + (return-type "void") + (params + ((type "Vector3") (name "position")) + ((type "float") (name "radiusTop")) + ((type "float") (name "radiusBottom")) + ((type "float") (name "height")) + ((type "int") (name "sides")) + ((type "Color") (name "color")))) + + ((name "DrawCylinderWiresEx") + (description "Draw a cylinder wires with base at startPos and top at endPos") + (return-type "void") + (params + ((type "Vector3") (name "startPos")) + ((type "Vector3") (name "endPos")) + ((type "float") (name "startRadius")) + ((type "float") (name "endRadius")) + ((type "int") (name "sides")) + ((type "Color") (name "color")))) + + ((name "DrawCapsule") + (description "Draw a capsule with the center of its sphere caps at startPos and endPos") + (return-type "void") + (params + ((type "Vector3") (name "startPos")) + ((type "Vector3") (name "endPos")) + ((type "float") (name "radius")) + ((type "int") (name "rings")) + ((type "int") (name "slices")) + ((type "Color") (name "color")))) + + ((name "DrawCapsuleWires") + (description "Draw capsule wireframe with the center of its sphere caps at startPos and endPos") + (return-type "void") + (params + ((type "Vector3") (name "startPos")) + ((type "Vector3") (name "endPos")) + ((type "float") (name "radius")) + ((type "int") (name "rings")) + ((type "int") (name "slices")) + ((type "Color") (name "color")))) + + ((name "DrawPlane") + (description "Draw a plane XZ") + (return-type "void") + (params + ((type "Vector3") (name "centerPos")) + ((type "Vector2") (name "size")) + ((type "Color") (name "color")))) + + ((name "DrawRay") + (description "Draw a ray line") + (return-type "void") + (params + ((type "Ray") (name "ray")) + ((type "Color") (name "color")))) + + ((name "DrawGrid") + (description "Draw a grid (centered at (0, 0, 0))") + (return-type "void") + (params + ((type "int") (name "slices")) + ((type "float") (name "spacing")))) + + ((name "LoadModel") + (description "Load model from files (meshes and materials)") + (return-type "Model") + (params + ((type "const char *") (name "fileName")))) + + ((name "LoadModelFromMesh") + (description "Load model from generated mesh (default material)") + (return-type "Model") + (params + ((type "Mesh") (name "mesh")))) + + ((name "IsModelValid") + (description "Check if model is valid (loaded in GPU, VAO/VBOs)") + (return-type "bool") + (params + ((type "Model") (name "model")))) + + ((name "UnloadModel") + (description "Unload model (including meshes) from memory (RAM and/or VRAM)") + (return-type "void") + (params + ((type "Model") (name "model")))) + + ((name "GetModelBoundingBox") + (description "Compute model bounding box limits (considers all meshes)") + (return-type "BoundingBox") + (params + ((type "Model") (name "model")))) + + ((name "DrawModel") + (description "Draw a model (with texture if set)") + (return-type "void") + (params + ((type "Model") (name "model")) + ((type "Vector3") (name "position")) + ((type "float") (name "scale")) + ((type "Color") (name "tint")))) + + ((name "DrawModelEx") + (description "Draw a model with custom transform") + (return-type "void") + (params + ((type "Model") (name "model")) + ((type "Vector3") (name "position")) + ((type "Vector3") (name "rotationAxis")) + ((type "float") (name "rotationAngle")) + ((type "Vector3") (name "scale")) + ((type "Color") (name "tint")))) + + ((name "DrawModelWires") + (description "Draw a model wires (with texture if set)") + (return-type "void") + (params + ((type "Model") (name "model")) + ((type "Vector3") (name "position")) + ((type "float") (name "scale")) + ((type "Color") (name "tint")))) + + ((name "DrawModelWiresEx") + (description "Draw a model wires with custom transform") + (return-type "void") + (params + ((type "Model") (name "model")) + ((type "Vector3") (name "position")) + ((type "Vector3") (name "rotationAxis")) + ((type "float") (name "rotationAngle")) + ((type "Vector3") (name "scale")) + ((type "Color") (name "tint")))) + + ((name "DrawBoundingBox") + (description "Draw bounding box (wires)") + (return-type "void") + (params + ((type "BoundingBox") (name "box")) + ((type "Color") (name "color")))) + + ((name "DrawBillboard") + (description "Draw a billboard texture") + (return-type "void") + (params + ((type "Camera") (name "camera")) + ((type "Texture2D") (name "texture")) + ((type "Vector3") (name "position")) + ((type "float") (name "scale")) + ((type "Color") (name "tint")))) + + ((name "DrawBillboardRec") + (description "Draw a billboard texture defined by rectangle") + (return-type "void") + (params + ((type "Camera") (name "camera")) + ((type "Texture2D") (name "texture")) + ((type "Rectangle") (name "rec")) + ((type "Vector3") (name "position")) + ((type "Vector2") (name "size")) + ((type "Color") (name "tint")))) + + ((name "DrawBillboardPro") + (description "Draw a billboard texture defined by source rectangle with scaling and rotation") + (return-type "void") + (params + ((type "Camera") (name "camera")) + ((type "Texture2D") (name "texture")) + ((type "Rectangle") (name "rec")) + ((type "Vector3") (name "position")) + ((type "Vector3") (name "up")) + ((type "Vector2") (name "size")) + ((type "Vector2") (name "origin")) + ((type "float") (name "rotation")) + ((type "Color") (name "tint")))) + + ((name "UploadMesh") + (description "Upload mesh vertex data in GPU and provide VAO/VBO ids") + (return-type "void") + (params + ((type "Mesh *") (name "mesh")) + ((type "bool") (name "dynamic")))) + + ((name "UpdateMeshBuffer") + (description "Update mesh vertex data in GPU for a specific buffer index") + (return-type "void") + (params + ((type "Mesh") (name "mesh")) + ((type "int") (name "index")) + ((type "const void *") (name "data")) + ((type "int") (name "dataSize")) + ((type "int") (name "offset")))) + + ((name "UnloadMesh") + (description "Unload mesh data from CPU and GPU") + (return-type "void") + (params + ((type "Mesh") (name "mesh")))) + + ((name "DrawMesh") + (description "Draw a 3d mesh with material and transform") + (return-type "void") + (params + ((type "Mesh") (name "mesh")) + ((type "Material") (name "material")) + ((type "Matrix") (name "transform")))) + + ((name "DrawMeshInstanced") + (description "Draw multiple mesh instances with material and different transforms") + (return-type "void") + (params + ((type "Mesh") (name "mesh")) + ((type "Material") (name "material")) + ((type "const Matrix *") (name "transforms")) + ((type "int") (name "instances")))) + + ((name "GetMeshBoundingBox") + (description "Compute mesh bounding box limits") + (return-type "BoundingBox") + (params + ((type "Mesh") (name "mesh")))) + + ((name "GenMeshTangents") + (description "Compute mesh tangents") + (return-type "void") + (params + ((type "Mesh *") (name "mesh")))) + + ((name "ExportMesh") + (description "Export mesh data to file, returns true on success") + (return-type "bool") + (params + ((type "Mesh") (name "mesh")) + ((type "const char *") (name "fileName")))) + + ((name "ExportMeshAsCode") + (description "Export mesh as code file (.h) defining multiple arrays of vertex attributes") + (return-type "bool") + (params + ((type "Mesh") (name "mesh")) + ((type "const char *") (name "fileName")))) + + ((name "GenMeshPoly") + (description "Generate polygonal mesh") + (return-type "Mesh") + (params + ((type "int") (name "sides")) + ((type "float") (name "radius")))) + + ((name "GenMeshPlane") + (description "Generate plane mesh (with subdivisions)") + (return-type "Mesh") + (params + ((type "float") (name "width")) + ((type "float") (name "length")) + ((type "int") (name "resX")) + ((type "int") (name "resZ")))) + + ((name "GenMeshCube") + (description "Generate cuboid mesh") + (return-type "Mesh") + (params + ((type "float") (name "width")) + ((type "float") (name "height")) + ((type "float") (name "length")))) + + ((name "GenMeshSphere") + (description "Generate sphere mesh (standard sphere)") + (return-type "Mesh") + (params + ((type "float") (name "radius")) + ((type "int") (name "rings")) + ((type "int") (name "slices")))) + + ((name "GenMeshHemiSphere") + (description "Generate half-sphere mesh (no bottom cap)") + (return-type "Mesh") + (params + ((type "float") (name "radius")) + ((type "int") (name "rings")) + ((type "int") (name "slices")))) + + ((name "GenMeshCylinder") + (description "Generate cylinder mesh") + (return-type "Mesh") + (params + ((type "float") (name "radius")) + ((type "float") (name "height")) + ((type "int") (name "slices")))) + + ((name "GenMeshCone") + (description "Generate cone/pyramid mesh") + (return-type "Mesh") + (params + ((type "float") (name "radius")) + ((type "float") (name "height")) + ((type "int") (name "slices")))) + + ((name "GenMeshTorus") + (description "Generate torus mesh") + (return-type "Mesh") + (params + ((type "float") (name "radius")) + ((type "float") (name "size")) + ((type "int") (name "radSeg")) + ((type "int") (name "sides")))) + + ((name "GenMeshKnot") + (description "Generate trefoil knot mesh") + (return-type "Mesh") + (params + ((type "float") (name "radius")) + ((type "float") (name "size")) + ((type "int") (name "radSeg")) + ((type "int") (name "sides")))) + + ((name "GenMeshHeightmap") + (description "Generate heightmap mesh from image data") + (return-type "Mesh") + (params + ((type "Image") (name "heightmap")) + ((type "Vector3") (name "size")))) + + ((name "GenMeshCubicmap") + (description "Generate cubes-based map mesh from image data") + (return-type "Mesh") + (params + ((type "Image") (name "cubicmap")) + ((type "Vector3") (name "cubeSize")))) + + ((name "LoadMaterials") + (description "Load materials from model file") + (return-type "Material *") + (params + ((type "const char *") (name "fileName")) + ((type "int *") (name "materialCount")))) + + ((name "LoadMaterialDefault") + (description "Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps)") + (return-type "Material")) + + ((name "IsMaterialValid") + (description "Check if material is valid (shader assigned, map textures loaded in GPU)") + (return-type "bool") + (params + ((type "Material") (name "material")))) + + ((name "UnloadMaterial") + (description "Unload material from GPU memory (VRAM)") + (return-type "void") + (params + ((type "Material") (name "material")))) + + ((name "SetMaterialTexture") + (description "Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...)") + (return-type "void") + (params + ((type "Material *") (name "material")) + ((type "int") (name "mapType")) + ((type "Texture2D") (name "texture")))) + + ((name "SetModelMeshMaterial") + (description "Set material for a mesh") + (return-type "void") + (params + ((type "Model *") (name "model")) + ((type "int") (name "meshId")) + ((type "int") (name "materialId")))) + + ((name "LoadModelAnimations") + (description "Load model animations from file") + (return-type "ModelAnimation *") + (params + ((type "const char *") (name "fileName")) + ((type "int *") (name "animCount")))) + + ((name "UpdateModelAnimation") + (description "Update model animation pose (vertex buffers and bone matrices)") + (return-type "void") + (params + ((type "Model") (name "model")) + ((type "ModelAnimation") (name "anim")) + ((type "float") (name "frame")))) + + ((name "UpdateModelAnimationEx") + (description "Update model animation pose, blending two animations") + (return-type "void") + (params + ((type "Model") (name "model")) + ((type "ModelAnimation") (name "animA")) + ((type "float") (name "frameA")) + ((type "ModelAnimation") (name "animB")) + ((type "float") (name "frameB")) + ((type "float") (name "blend")))) + + ((name "UnloadModelAnimations") + (description "Unload animation array data") + (return-type "void") + (params + ((type "ModelAnimation *") (name "animations")) + ((type "int") (name "animCount")))) + + ((name "IsModelAnimationValid") + (description "Check model animation skeleton match") + (return-type "bool") + (params + ((type "Model") (name "model")) + ((type "ModelAnimation") (name "anim")))) + + ((name "CheckCollisionSpheres") + (description "Check collision between two spheres") + (return-type "bool") + (params + ((type "Vector3") (name "center1")) + ((type "float") (name "radius1")) + ((type "Vector3") (name "center2")) + ((type "float") (name "radius2")))) + + ((name "CheckCollisionBoxes") + (description "Check collision between two bounding boxes") + (return-type "bool") + (params + ((type "BoundingBox") (name "box1")) + ((type "BoundingBox") (name "box2")))) + + ((name "CheckCollisionBoxSphere") + (description "Check collision between box and sphere") + (return-type "bool") + (params + ((type "BoundingBox") (name "box")) + ((type "Vector3") (name "center")) + ((type "float") (name "radius")))) + + ((name "GetRayCollisionSphere") + (description "Get collision info between ray and sphere") + (return-type "RayCollision") + (params + ((type "Ray") (name "ray")) + ((type "Vector3") (name "center")) + ((type "float") (name "radius")))) + + ((name "GetRayCollisionBox") + (description "Get collision info between ray and box") + (return-type "RayCollision") + (params + ((type "Ray") (name "ray")) + ((type "BoundingBox") (name "box")))) + + ((name "GetRayCollisionMesh") + (description "Get collision info between ray and mesh") + (return-type "RayCollision") + (params + ((type "Ray") (name "ray")) + ((type "Mesh") (name "mesh")) + ((type "Matrix") (name "transform")))) + + ((name "GetRayCollisionTriangle") + (description "Get collision info between ray and triangle") + (return-type "RayCollision") + (params + ((type "Ray") (name "ray")) + ((type "Vector3") (name "p1")) + ((type "Vector3") (name "p2")) + ((type "Vector3") (name "p3")))) + + ((name "GetRayCollisionQuad") + (description "Get collision info between ray and quad") + (return-type "RayCollision") + (params + ((type "Ray") (name "ray")) + ((type "Vector3") (name "p1")) + ((type "Vector3") (name "p2")) + ((type "Vector3") (name "p3")) + ((type "Vector3") (name "p4")))) + + ((name "InitAudioDevice") + (description "Initialize audio device and context") + (return-type "void")) + + ((name "CloseAudioDevice") + (description "Close the audio device and context") + (return-type "void")) + + ((name "IsAudioDeviceReady") + (description "Check if audio device has been initialized successfully") + (return-type "bool")) + + ((name "SetMasterVolume") + (description "Set master volume (listener)") + (return-type "void") + (params + ((type "float") (name "volume")))) + + ((name "GetMasterVolume") + (description "Get master volume (listener)") + (return-type "float")) + + ((name "LoadWave") + (description "Load wave data from file") + (return-type "Wave") + (params + ((type "const char *") (name "fileName")))) + + ((name "LoadWaveFromMemory") + (description "Load wave from memory buffer, fileType refers to extension: i.e. '.wav'") + (return-type "Wave") + (params + ((type "const char *") (name "fileType")) + ((type "const unsigned char *") (name "fileData")) + ((type "int") (name "dataSize")))) + + ((name "IsWaveValid") + (description "Check if wave data is valid (data loaded and parameters)") + (return-type "bool") + (params + ((type "Wave") (name "wave")))) + + ((name "LoadSound") + (description "Load sound from file") + (return-type "Sound") + (params + ((type "const char *") (name "fileName")))) + + ((name "LoadSoundFromWave") + (description "Load sound from wave data") + (return-type "Sound") + (params + ((type "Wave") (name "wave")))) + + ((name "LoadSoundAlias") + (description "Load sound alias, new sound that shares the same sample data as the source sound, does not own the sound data") + (return-type "Sound") + (params + ((type "Sound") (name "source")))) + + ((name "IsSoundValid") + (description "Check if sound is valid (data loaded and buffers initialized)") + (return-type "bool") + (params + ((type "Sound") (name "sound")))) + + ((name "UpdateSound") + (description "Update sound buffer with new data (default data format: 32 bit float, stereo)") + (return-type "void") + (params + ((type "Sound") (name "sound")) + ((type "const void *") (name "data")) + ((type "int") (name "frameCount")))) + + ((name "UnloadWave") + (description "Unload wave data") + (return-type "void") + (params + ((type "Wave") (name "wave")))) + + ((name "UnloadSound") + (description "Unload sound") + (return-type "void") + (params + ((type "Sound") (name "sound")))) + + ((name "UnloadSoundAlias") + (description "Unload sound alias (does not deallocate sample data)") + (return-type "void") + (params + ((type "Sound") (name "alias")))) + + ((name "ExportWave") + (description "Export wave data to file, returns true on success") + (return-type "bool") + (params + ((type "Wave") (name "wave")) + ((type "const char *") (name "fileName")))) + + ((name "ExportWaveAsCode") + (description "Export wave sample data to code (.h), returns true on success") + (return-type "bool") + (params + ((type "Wave") (name "wave")) + ((type "const char *") (name "fileName")))) + + ((name "PlaySound") + (description "Play a sound") + (return-type "void") + (params + ((type "Sound") (name "sound")))) + + ((name "StopSound") + (description "Stop playing a sound") + (return-type "void") + (params + ((type "Sound") (name "sound")))) + + ((name "PauseSound") + (description "Pause a sound") + (return-type "void") + (params + ((type "Sound") (name "sound")))) + + ((name "ResumeSound") + (description "Resume a paused sound") + (return-type "void") + (params + ((type "Sound") (name "sound")))) + + ((name "IsSoundPlaying") + (description "Check if sound is currently playing") + (return-type "bool") + (params + ((type "Sound") (name "sound")))) + + ((name "SetSoundVolume") + (description "Set volume for a sound (1.0 is max level)") + (return-type "void") + (params + ((type "Sound") (name "sound")) + ((type "float") (name "volume")))) + + ((name "SetSoundPitch") + (description "Set pitch for a sound (1.0 is base level)") + (return-type "void") + (params + ((type "Sound") (name "sound")) + ((type "float") (name "pitch")))) + + ((name "SetSoundPan") + (description "Set pan for a sound (-1.0 left, 0.0 center, 1.0 right)") + (return-type "void") + (params + ((type "Sound") (name "sound")) + ((type "float") (name "pan")))) + + ((name "WaveCopy") + (description "Copy a wave to a new wave") + (return-type "Wave") + (params + ((type "Wave") (name "wave")))) + + ((name "WaveCrop") + (description "Crop a wave to defined frames range") + (return-type "void") + (params + ((type "Wave *") (name "wave")) + ((type "int") (name "initFrame")) + ((type "int") (name "finalFrame")))) + + ((name "WaveFormat") + (description "Convert wave data to desired format") + (return-type "void") + (params + ((type "Wave *") (name "wave")) + ((type "int") (name "sampleRate")) + ((type "int") (name "sampleSize")) + ((type "int") (name "channels")))) + + ((name "LoadWaveSamples") + (description "Load samples data from wave as a 32bit float data array") + (return-type "float *") + (params + ((type "Wave") (name "wave")))) + + ((name "UnloadWaveSamples") + (description "Unload samples data loaded with LoadWaveSamples()") + (return-type "void") + (params + ((type "float *") (name "samples")))) + + ((name "LoadMusicStream") + (description "Load music stream from file") + (return-type "Music") + (params + ((type "const char *") (name "fileName")))) + + ((name "LoadMusicStreamFromMemory") + (description "Load music stream from data") + (return-type "Music") + (params + ((type "const char *") (name "fileType")) + ((type "const unsigned char *") (name "data")) + ((type "int") (name "dataSize")))) + + ((name "IsMusicValid") + (description "Check if music stream is valid (context and buffers initialized)") + (return-type "bool") + (params + ((type "Music") (name "music")))) + + ((name "UnloadMusicStream") + (description "Unload music stream") + (return-type "void") + (params + ((type "Music") (name "music")))) + + ((name "PlayMusicStream") + (description "Start music playing") + (return-type "void") + (params + ((type "Music") (name "music")))) + + ((name "IsMusicStreamPlaying") + (description "Check if music is playing") + (return-type "bool") + (params + ((type "Music") (name "music")))) + + ((name "UpdateMusicStream") + (description "Update buffers for music streaming") + (return-type "void") + (params + ((type "Music") (name "music")))) + + ((name "StopMusicStream") + (description "Stop music playing") + (return-type "void") + (params + ((type "Music") (name "music")))) + + ((name "PauseMusicStream") + (description "Pause music playing") + (return-type "void") + (params + ((type "Music") (name "music")))) + + ((name "ResumeMusicStream") + (description "Resume playing paused music") + (return-type "void") + (params + ((type "Music") (name "music")))) + + ((name "SeekMusicStream") + (description "Seek music to a position (in seconds)") + (return-type "void") + (params + ((type "Music") (name "music")) + ((type "float") (name "position")))) + + ((name "SetMusicVolume") + (description "Set volume for music (1.0 is max level)") + (return-type "void") + (params + ((type "Music") (name "music")) + ((type "float") (name "volume")))) + + ((name "SetMusicPitch") + (description "Set pitch for music (1.0 is base level)") + (return-type "void") + (params + ((type "Music") (name "music")) + ((type "float") (name "pitch")))) + + ((name "SetMusicPan") + (description "Set pan for music (-1.0 left, 0.0 center, 1.0 right)") + (return-type "void") + (params + ((type "Music") (name "music")) + ((type "float") (name "pan")))) + + ((name "GetMusicTimeLength") + (description "Get music time length (in seconds)") + (return-type "float") + (params + ((type "Music") (name "music")))) + + ((name "GetMusicTimePlayed") + (description "Get current music time played (in seconds)") + (return-type "float") + (params + ((type "Music") (name "music")))) + + ((name "LoadAudioStream") + (description "Load audio stream (to stream raw audio pcm data)") + (return-type "AudioStream") + (params + ((type "unsigned int") (name "sampleRate")) + ((type "unsigned int") (name "sampleSize")) + ((type "unsigned int") (name "channels")))) + + ((name "IsAudioStreamValid") + (description "Check if an audio stream is valid (buffers initialized)") + (return-type "bool") + (params + ((type "AudioStream") (name "stream")))) + + ((name "UnloadAudioStream") + (description "Unload audio stream and free memory") + (return-type "void") + (params + ((type "AudioStream") (name "stream")))) + + ((name "UpdateAudioStream") + (description "Update audio stream buffers with data") + (return-type "void") + (params + ((type "AudioStream") (name "stream")) + ((type "const void *") (name "data")) + ((type "int") (name "frameCount")))) + + ((name "IsAudioStreamProcessed") + (description "Check if any audio stream buffers requires refill") + (return-type "bool") + (params + ((type "AudioStream") (name "stream")))) + + ((name "PlayAudioStream") + (description "Play audio stream") + (return-type "void") + (params + ((type "AudioStream") (name "stream")))) + + ((name "PauseAudioStream") + (description "Pause audio stream") + (return-type "void") + (params + ((type "AudioStream") (name "stream")))) + + ((name "ResumeAudioStream") + (description "Resume audio stream") + (return-type "void") + (params + ((type "AudioStream") (name "stream")))) + + ((name "IsAudioStreamPlaying") + (description "Check if audio stream is playing") + (return-type "bool") + (params + ((type "AudioStream") (name "stream")))) + + ((name "StopAudioStream") + (description "Stop audio stream") + (return-type "void") + (params + ((type "AudioStream") (name "stream")))) + + ((name "SetAudioStreamVolume") + (description "Set volume for audio stream (1.0 is max level)") + (return-type "void") + (params + ((type "AudioStream") (name "stream")) + ((type "float") (name "volume")))) + + ((name "SetAudioStreamPitch") + (description "Set pitch for audio stream (1.0 is base level)") + (return-type "void") + (params + ((type "AudioStream") (name "stream")) + ((type "float") (name "pitch")))) + + ((name "SetAudioStreamPan") + (description "Set pan for audio stream (-1.0 left, 0.0 center, 1.0 right)") + (return-type "void") + (params + ((type "AudioStream") (name "stream")) + ((type "float") (name "pan")))) + + ((name "SetAudioStreamBufferSizeDefault") + (description "Default size for new audio streams") + (return-type "void") + (params + ((type "int") (name "size")))) + + ((name "SetAudioStreamCallback") + (description "Audio thread callback to request new data") + (return-type "void") + (params + ((type "AudioStream") (name "stream")) + ((type "AudioCallback") (name "callback")))) + + ((name "AttachAudioStreamProcessor") + (description "Attach audio stream processor to stream, receives frames x 2 samples as 'float' (stereo)") + (return-type "void") + (params + ((type "AudioStream") (name "stream")) + ((type "AudioCallback") (name "processor")))) + + ((name "DetachAudioStreamProcessor") + (description "Detach audio stream processor from stream") + (return-type "void") + (params + ((type "AudioStream") (name "stream")) + ((type "AudioCallback") (name "processor")))) + + ((name "AttachAudioMixedProcessor") + (description "Attach audio stream processor to the entire audio pipeline, receives frames x 2 samples as 'float' (stereo)") + (return-type "void") + (params + ((type "AudioCallback") (name "processor")))) + + ((name "DetachAudioMixedProcessor") + (description "Detach audio stream processor from the entire audio pipeline") + (return-type "void") + (params + ((type "AudioCallback") (name "processor")))))) diff --git a/tools/rlparser/output/raylib_api.txt b/tools/rlparser/output/raylib_api.txt index 52fd63710..47b5fd6f3 100644 --- a/tools/rlparser/output/raylib_api.txt +++ b/tools/rlparser/output/raylib_api.txt @@ -995,7 +995,7 @@ Callback 006: AudioCallback() (2 input parameters) Param[1]: bufferData (type: void *) Param[2]: frames (type: unsigned int) -Functions found: 607 +Functions found: 611 Function 001: InitWindow() (3 input parameters) Name: InitWindow @@ -3244,7 +3244,16 @@ Function 361: ImageDrawRectangleRec() (3 input parameters) Param[1]: dst (type: Image *) Param[2]: rec (type: Rectangle) Param[3]: color (type: Color) -Function 362: ImageDrawRectangleLines() (6 input parameters) +Function 362: ImageDrawRectanglePro() (5 input parameters) + Name: ImageDrawRectanglePro + Return type: void + Description: Draw a color-filled rectangle with pro parameters within and image + Param[1]: dst (type: Image *) + Param[2]: rec (type: Rectangle) + Param[3]: origin (type: Vector2) + Param[4]: rotation (type: float) + Param[5]: color (type: Color) +Function 363: ImageDrawRectangleLines() (6 input parameters) Name: ImageDrawRectangleLines Return type: void Description: Draw rectangle lines within an image @@ -3254,7 +3263,7 @@ Function 362: ImageDrawRectangleLines() (6 input parameters) Param[4]: width (type: int) Param[5]: height (type: int) Param[6]: color (type: Color) -Function 363: ImageDrawRectangleLinesEx() (4 input parameters) +Function 364: ImageDrawRectangleLinesEx() (4 input parameters) Name: ImageDrawRectangleLinesEx Return type: void Description: Draw rectangle lines within an image with line thickness @@ -3262,7 +3271,17 @@ Function 363: ImageDrawRectangleLinesEx() (4 input parameters) Param[2]: rec (type: Rectangle) Param[3]: thick (type: int) Param[4]: color (type: Color) -Function 364: ImageDrawCircle() (5 input parameters) +Function 365: ImageDrawRectangleGradientEx() (6 input parameters) + Name: ImageDrawRectangleGradientEx + Return type: void + Description: Draw rectangle with gradient colors within an image, counter-clockwise color order + Param[1]: dst (type: Image *) + Param[2]: rec (type: Rectangle) + Param[3]: col1 (type: Color) + Param[4]: col2 (type: Color) + Param[5]: col3 (type: Color) + Param[6]: col4 (type: Color) +Function 366: ImageDrawCircle() (5 input parameters) Name: ImageDrawCircle Return type: void Description: Draw a filled circle within an image @@ -3271,7 +3290,7 @@ Function 364: ImageDrawCircle() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 365: ImageDrawCircleV() (4 input parameters) +Function 367: ImageDrawCircleV() (4 input parameters) Name: ImageDrawCircleV Return type: void Description: Draw a filled circle within an image (Vector version) @@ -3279,7 +3298,7 @@ Function 365: ImageDrawCircleV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 366: ImageDrawCircleLines() (5 input parameters) +Function 368: ImageDrawCircleLines() (5 input parameters) Name: ImageDrawCircleLines Return type: void Description: Draw circle outline within an image @@ -3288,7 +3307,7 @@ Function 366: ImageDrawCircleLines() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 367: ImageDrawCircleLinesV() (4 input parameters) +Function 369: ImageDrawCircleLinesV() (4 input parameters) Name: ImageDrawCircleLinesV Return type: void Description: Draw circle outline within an image (Vector version) @@ -3296,7 +3315,7 @@ Function 367: ImageDrawCircleLinesV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 368: ImageDrawCircleGradient() (5 input parameters) +Function 370: ImageDrawCircleGradient() (5 input parameters) Name: ImageDrawCircleGradient Return type: void Description: Draw a gradient-filled circle within an image @@ -3305,7 +3324,7 @@ Function 368: ImageDrawCircleGradient() (5 input parameters) Param[3]: radius (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 369: ImageDrawImage() (5 input parameters) +Function 371: ImageDrawImage() (5 input parameters) Name: ImageDrawImage Return type: void Description: Draw an image within an image @@ -3314,7 +3333,17 @@ Function 369: ImageDrawImage() (5 input parameters) Param[3]: posX (type: int) Param[4]: posY (type: int) Param[5]: tint (type: Color) -Function 370: ImageDrawImageRec() (5 input parameters) +Function 372: ImageDrawImageEx() (6 input parameters) + Name: ImageDrawImageEx + Return type: void + Description: Draw an image with scaling and rotation within an image + Param[1]: dst (type: Image *) + Param[2]: src (type: Image) + Param[3]: position (type: Vector2) + Param[4]: rotation (type: float) + Param[5]: scale (type: float) + Param[6]: tint (type: Color) +Function 373: ImageDrawImageRec() (5 input parameters) Name: ImageDrawImageRec Return type: void Description: Draw a part of an image defined by a rectangle within an image @@ -3323,7 +3352,7 @@ Function 370: ImageDrawImageRec() (5 input parameters) Param[3]: srcRec (type: Rectangle) Param[4]: position (type: Vector2) Param[5]: tint (type: Color) -Function 371: ImageDrawImagePro() (7 input parameters) +Function 374: ImageDrawImagePro() (7 input parameters) Name: ImageDrawImagePro Return type: void Description: Draw a part of an image defined by a rectangle into destination rectangle, with scaling and rotation, within an image @@ -3334,7 +3363,7 @@ Function 371: ImageDrawImagePro() (7 input parameters) Param[5]: origin (type: Vector2) Param[6]: rotation (type: float) Param[7]: tint (type: Color) -Function 372: ImageDrawText() (6 input parameters) +Function 375: ImageDrawText() (6 input parameters) Name: ImageDrawText Return type: void Description: Draw text (using default font) within an image (destination) @@ -3344,7 +3373,7 @@ Function 372: ImageDrawText() (6 input parameters) Param[4]: posY (type: int) Param[5]: fontSize (type: int) Param[6]: color (type: Color) -Function 373: ImageDrawTextEx() (7 input parameters) +Function 376: ImageDrawTextEx() (7 input parameters) Name: ImageDrawTextEx Return type: void Description: Draw text (custom sprite font) within an image (destination) @@ -3355,79 +3384,92 @@ Function 373: ImageDrawTextEx() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 374: LoadTexture() (1 input parameters) +Function 377: ImageDrawTextPro() (9 input parameters) + Name: ImageDrawTextPro + Return type: void + Description: Draw text using Font and pro parameters (rotation) + Param[1]: dst (type: Image *) + Param[2]: font (type: Font) + Param[3]: text (type: const char *) + Param[4]: position (type: Vector2) + Param[5]: origin (type: Vector2) + Param[6]: rotation (type: float) + Param[7]: fontSize (type: float) + Param[8]: spacing (type: float) + Param[9]: tint (type: Color) +Function 378: LoadTexture() (1 input parameters) Name: LoadTexture Return type: Texture2D Description: Load texture from file into GPU memory (VRAM) Param[1]: fileName (type: const char *) -Function 375: LoadTextureFromImage() (1 input parameters) +Function 379: LoadTextureFromImage() (1 input parameters) Name: LoadTextureFromImage Return type: Texture2D Description: Load texture from image data Param[1]: image (type: Image) -Function 376: LoadTextureCubemap() (2 input parameters) +Function 380: LoadTextureCubemap() (2 input parameters) Name: LoadTextureCubemap Return type: TextureCubemap Description: Load cubemap from image, multiple image cubemap layouts supported Param[1]: image (type: Image) Param[2]: layout (type: int) -Function 377: LoadRenderTexture() (2 input parameters) +Function 381: LoadRenderTexture() (2 input parameters) Name: LoadRenderTexture Return type: RenderTexture2D Description: Load texture for rendering (framebuffer) Param[1]: width (type: int) Param[2]: height (type: int) -Function 378: IsTextureValid() (1 input parameters) +Function 382: IsTextureValid() (1 input parameters) Name: IsTextureValid Return type: bool Description: Check if texture is valid (loaded in GPU) Param[1]: texture (type: Texture2D) -Function 379: UnloadTexture() (1 input parameters) +Function 383: UnloadTexture() (1 input parameters) Name: UnloadTexture Return type: void Description: Unload texture from GPU memory (VRAM) Param[1]: texture (type: Texture2D) -Function 380: IsRenderTextureValid() (1 input parameters) +Function 384: IsRenderTextureValid() (1 input parameters) Name: IsRenderTextureValid Return type: bool Description: Check if render texture is valid (loaded in GPU) Param[1]: target (type: RenderTexture2D) -Function 381: UnloadRenderTexture() (1 input parameters) +Function 385: UnloadRenderTexture() (1 input parameters) Name: UnloadRenderTexture Return type: void Description: Unload render texture from GPU memory (VRAM) Param[1]: target (type: RenderTexture2D) -Function 382: UpdateTexture() (2 input parameters) +Function 386: UpdateTexture() (2 input parameters) Name: UpdateTexture Return type: void Description: Update GPU texture with new data (pixels should be able to fill texture) Param[1]: texture (type: Texture2D) Param[2]: pixels (type: const void *) -Function 383: UpdateTextureRec() (3 input parameters) +Function 387: UpdateTextureRec() (3 input parameters) Name: UpdateTextureRec Return type: void Description: Update GPU texture rectangle with new data (pixels and rec should fit in texture) Param[1]: texture (type: Texture2D) Param[2]: rec (type: Rectangle) Param[3]: pixels (type: const void *) -Function 384: GenTextureMipmaps() (1 input parameters) +Function 388: GenTextureMipmaps() (1 input parameters) Name: GenTextureMipmaps Return type: void Description: Generate GPU mipmaps for a texture Param[1]: texture (type: Texture2D *) -Function 385: SetTextureFilter() (2 input parameters) +Function 389: SetTextureFilter() (2 input parameters) Name: SetTextureFilter Return type: void Description: Set texture scaling filter mode Param[1]: texture (type: Texture2D) Param[2]: filter (type: int) -Function 386: SetTextureWrap() (2 input parameters) +Function 390: SetTextureWrap() (2 input parameters) Name: SetTextureWrap Return type: void Description: Set texture wrapping mode Param[1]: texture (type: Texture2D) Param[2]: wrap (type: int) -Function 387: DrawTexture() (4 input parameters) +Function 391: DrawTexture() (4 input parameters) Name: DrawTexture Return type: void Description: Draw a Texture2D @@ -3435,14 +3477,14 @@ Function 387: DrawTexture() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: tint (type: Color) -Function 388: DrawTextureV() (3 input parameters) +Function 392: DrawTextureV() (3 input parameters) Name: DrawTextureV Return type: void Description: Draw a Texture2D with position defined as Vector2 Param[1]: texture (type: Texture2D) Param[2]: position (type: Vector2) Param[3]: tint (type: Color) -Function 389: DrawTextureEx() (5 input parameters) +Function 393: DrawTextureEx() (5 input parameters) Name: DrawTextureEx Return type: void Description: Draw a Texture2D with rotation and scale @@ -3451,7 +3493,7 @@ Function 389: DrawTextureEx() (5 input parameters) Param[3]: rotation (type: float) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 390: DrawTextureRec() (4 input parameters) +Function 394: DrawTextureRec() (4 input parameters) Name: DrawTextureRec Return type: void Description: Draw a part of a texture defined by a rectangle @@ -3459,7 +3501,7 @@ Function 390: DrawTextureRec() (4 input parameters) Param[2]: rec (type: Rectangle) Param[3]: position (type: Vector2) Param[4]: tint (type: Color) -Function 391: DrawTexturePro() (6 input parameters) +Function 395: DrawTexturePro() (6 input parameters) Name: DrawTexturePro Return type: void Description: Draw a part of a texture defined by a source rectangle to destination rectangle, with scaling and rotation @@ -3469,7 +3511,7 @@ Function 391: DrawTexturePro() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 392: DrawTextureNPatch() (6 input parameters) +Function 396: DrawTextureNPatch() (6 input parameters) Name: DrawTextureNPatch Return type: void Description: Draw a texture (or part of it) that stretches or shrinks nicely @@ -3479,119 +3521,119 @@ Function 392: DrawTextureNPatch() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 393: ColorIsEqual() (2 input parameters) +Function 397: ColorIsEqual() (2 input parameters) Name: ColorIsEqual Return type: bool Description: Check if two colors are equal Param[1]: col1 (type: Color) Param[2]: col2 (type: Color) -Function 394: Fade() (2 input parameters) +Function 398: Fade() (2 input parameters) Name: Fade Return type: Color Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f Param[1]: color (type: Color) Param[2]: alpha (type: float) -Function 395: ColorToInt() (1 input parameters) +Function 399: ColorToInt() (1 input parameters) Name: ColorToInt Return type: int Description: Get hexadecimal value for a Color (0xRRGGBBAA) Param[1]: color (type: Color) -Function 396: ColorNormalize() (1 input parameters) +Function 400: ColorNormalize() (1 input parameters) Name: ColorNormalize Return type: Vector4 Description: Get Color normalized as float [0..1] Param[1]: color (type: Color) -Function 397: ColorFromNormalized() (1 input parameters) +Function 401: ColorFromNormalized() (1 input parameters) Name: ColorFromNormalized Return type: Color Description: Get Color from normalized values [0..1] Param[1]: normalized (type: Vector4) -Function 398: ColorToHSV() (1 input parameters) +Function 402: ColorToHSV() (1 input parameters) Name: ColorToHSV Return type: Vector3 Description: Get HSV values for a Color, hue [0..360], saturation/value [0..1] Param[1]: color (type: Color) -Function 399: ColorFromHSV() (3 input parameters) +Function 403: ColorFromHSV() (3 input parameters) Name: ColorFromHSV Return type: Color Description: Get a Color from HSV values, hue [0..360], saturation/value [0..1] Param[1]: hue (type: float) Param[2]: saturation (type: float) Param[3]: value (type: float) -Function 400: ColorTint() (2 input parameters) +Function 404: ColorTint() (2 input parameters) Name: ColorTint Return type: Color Description: Get color multiplied with another color Param[1]: color (type: Color) Param[2]: tint (type: Color) -Function 401: ColorBrightness() (2 input parameters) +Function 405: ColorBrightness() (2 input parameters) Name: ColorBrightness Return type: Color Description: Get color with brightness correction, brightness factor goes from -1.0f to 1.0f Param[1]: color (type: Color) Param[2]: factor (type: float) -Function 402: ColorContrast() (2 input parameters) +Function 406: ColorContrast() (2 input parameters) Name: ColorContrast Return type: Color Description: Get color with contrast correction, contrast values between -1.0f and 1.0f Param[1]: color (type: Color) Param[2]: contrast (type: float) -Function 403: ColorAlpha() (2 input parameters) +Function 407: ColorAlpha() (2 input parameters) Name: ColorAlpha Return type: Color Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f Param[1]: color (type: Color) Param[2]: alpha (type: float) -Function 404: ColorAlphaBlend() (3 input parameters) +Function 408: ColorAlphaBlend() (3 input parameters) Name: ColorAlphaBlend Return type: Color Description: Get src alpha-blended into dst color with tint Param[1]: dst (type: Color) Param[2]: src (type: Color) Param[3]: tint (type: Color) -Function 405: ColorLerp() (3 input parameters) +Function 409: ColorLerp() (3 input parameters) Name: ColorLerp Return type: Color Description: Get color lerp interpolation between two colors, factor [0.0f..1.0f] Param[1]: color1 (type: Color) Param[2]: color2 (type: Color) Param[3]: factor (type: float) -Function 406: GetColor() (1 input parameters) +Function 410: GetColor() (1 input parameters) Name: GetColor Return type: Color Description: Get Color structure from hexadecimal value Param[1]: hexValue (type: unsigned int) -Function 407: GetPixelColor() (2 input parameters) +Function 411: GetPixelColor() (2 input parameters) Name: GetPixelColor Return type: Color Description: Get Color from a source pixel pointer of certain format Param[1]: srcPtr (type: const void *) Param[2]: format (type: int) -Function 408: SetPixelColor() (3 input parameters) +Function 412: SetPixelColor() (3 input parameters) Name: SetPixelColor Return type: void Description: Set color formatted into destination pixel pointer Param[1]: dstPtr (type: void *) Param[2]: color (type: Color) Param[3]: format (type: int) -Function 409: GetPixelDataSize() (3 input parameters) +Function 413: GetPixelDataSize() (3 input parameters) Name: GetPixelDataSize Return type: int Description: Get pixel data size in bytes for certain format Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: format (type: int) -Function 410: GetFontDefault() (0 input parameters) +Function 414: GetFontDefault() (0 input parameters) Name: GetFontDefault Return type: Font Description: Get the default Font No input parameters -Function 411: LoadFont() (1 input parameters) +Function 415: LoadFont() (1 input parameters) Name: LoadFont Return type: Font Description: Load font from file into GPU memory (VRAM) Param[1]: fileName (type: const char *) -Function 412: LoadFontEx() (4 input parameters) +Function 416: LoadFontEx() (4 input parameters) Name: LoadFontEx Return type: Font Description: Load font from file with defined codepoints and generation size, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height @@ -3599,14 +3641,14 @@ Function 412: LoadFontEx() (4 input parameters) Param[2]: fontSize (type: int) Param[3]: codepoints (type: const int *) Param[4]: codepointCount (type: int) -Function 413: LoadFontFromImage() (3 input parameters) +Function 417: LoadFontFromImage() (3 input parameters) Name: LoadFontFromImage Return type: Font Description: Load font from Image (XNA style) Param[1]: image (type: Image) Param[2]: key (type: Color) Param[3]: firstChar (type: int) -Function 414: LoadFontFromMemory() (6 input parameters) +Function 418: LoadFontFromMemory() (6 input parameters) Name: LoadFontFromMemory Return type: Font Description: Load font from memory buffer, fileType refers to extension: i.e. '.ttf' @@ -3616,12 +3658,12 @@ Function 414: LoadFontFromMemory() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: codepoints (type: const int *) Param[6]: codepointCount (type: int) -Function 415: IsFontValid() (1 input parameters) +Function 419: IsFontValid() (1 input parameters) Name: IsFontValid Return type: bool Description: Check if font is valid (font data loaded, WARNING: GPU texture not checked) Param[1]: font (type: Font) -Function 416: LoadFontData() (7 input parameters) +Function 420: LoadFontData() (7 input parameters) Name: LoadFontData Return type: GlyphInfo * Description: Load font data for further use @@ -3632,7 +3674,7 @@ Function 416: LoadFontData() (7 input parameters) Param[5]: codepointCount (type: int) Param[6]: type (type: int) Param[7]: glyphCount (type: int *) -Function 417: GenImageFontAtlas() (6 input parameters) +Function 421: GenImageFontAtlas() (6 input parameters) Name: GenImageFontAtlas Return type: Image Description: Generate image font atlas using chars info @@ -3642,30 +3684,30 @@ Function 417: GenImageFontAtlas() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: padding (type: int) Param[6]: packMethod (type: int) -Function 418: UnloadFontData() (2 input parameters) +Function 422: UnloadFontData() (2 input parameters) Name: UnloadFontData Return type: void Description: Unload font chars info data (RAM) Param[1]: glyphs (type: GlyphInfo *) Param[2]: glyphCount (type: int) -Function 419: UnloadFont() (1 input parameters) +Function 423: UnloadFont() (1 input parameters) Name: UnloadFont Return type: void Description: Unload font from GPU memory (VRAM) Param[1]: font (type: Font) -Function 420: ExportFontAsCode() (2 input parameters) +Function 424: ExportFontAsCode() (2 input parameters) Name: ExportFontAsCode Return type: bool Description: Export font as code file, returns true on success Param[1]: font (type: Font) Param[2]: fileName (type: const char *) -Function 421: DrawFPS() (2 input parameters) +Function 425: DrawFPS() (2 input parameters) Name: DrawFPS Return type: void Description: Draw current FPS Param[1]: posX (type: int) Param[2]: posY (type: int) -Function 422: DrawText() (5 input parameters) +Function 426: DrawText() (5 input parameters) Name: DrawText Return type: void Description: Draw text (using default font) @@ -3674,7 +3716,7 @@ Function 422: DrawText() (5 input parameters) Param[3]: posY (type: int) Param[4]: fontSize (type: int) Param[5]: color (type: Color) -Function 423: DrawTextEx() (6 input parameters) +Function 427: DrawTextEx() (6 input parameters) Name: DrawTextEx Return type: void Description: Draw text using font and additional parameters @@ -3684,7 +3726,7 @@ Function 423: DrawTextEx() (6 input parameters) Param[4]: fontSize (type: float) Param[5]: spacing (type: float) Param[6]: tint (type: Color) -Function 424: DrawTextPro() (8 input parameters) +Function 428: DrawTextPro() (8 input parameters) Name: DrawTextPro Return type: void Description: Draw text using Font and pro parameters (rotation) @@ -3696,7 +3738,7 @@ Function 424: DrawTextPro() (8 input parameters) Param[6]: fontSize (type: float) Param[7]: spacing (type: float) Param[8]: tint (type: Color) -Function 425: DrawTextCodepoint() (5 input parameters) +Function 429: DrawTextCodepoint() (5 input parameters) Name: DrawTextCodepoint Return type: void Description: Draw one character (codepoint) @@ -3705,7 +3747,7 @@ Function 425: DrawTextCodepoint() (5 input parameters) Param[3]: position (type: Vector2) Param[4]: fontSize (type: float) Param[5]: tint (type: Color) -Function 426: DrawTextCodepoints() (7 input parameters) +Function 430: DrawTextCodepoints() (7 input parameters) Name: DrawTextCodepoints Return type: void Description: Draw multiple characters (codepoint) @@ -3716,18 +3758,18 @@ Function 426: DrawTextCodepoints() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 427: SetTextLineSpacing() (1 input parameters) +Function 431: SetTextLineSpacing() (1 input parameters) Name: SetTextLineSpacing Return type: void Description: Set vertical line spacing when drawing with line-breaks Param[1]: spacing (type: int) -Function 428: MeasureText() (2 input parameters) +Function 432: MeasureText() (2 input parameters) Name: MeasureText Return type: int Description: Measure string width for default font Param[1]: text (type: const char *) Param[2]: fontSize (type: int) -Function 429: MeasureTextEx() (4 input parameters) +Function 433: MeasureTextEx() (4 input parameters) Name: MeasureTextEx Return type: Vector2 Description: Measure string size for Font @@ -3735,7 +3777,7 @@ Function 429: MeasureTextEx() (4 input parameters) Param[2]: text (type: const char *) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) -Function 430: MeasureTextCodepoints() (5 input parameters) +Function 434: MeasureTextCodepoints() (5 input parameters) Name: MeasureTextCodepoints Return type: Vector2 Description: Measure string size for an existing array of codepoints for Font @@ -3744,144 +3786,144 @@ Function 430: MeasureTextCodepoints() (5 input parameters) Param[3]: length (type: int) Param[4]: fontSize (type: float) Param[5]: spacing (type: float) -Function 431: GetGlyphIndex() (2 input parameters) +Function 435: GetGlyphIndex() (2 input parameters) Name: GetGlyphIndex Return type: int Description: Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found Param[1]: font (type: Font) Param[2]: codepoint (type: int) -Function 432: GetGlyphInfo() (2 input parameters) +Function 436: GetGlyphInfo() (2 input parameters) Name: GetGlyphInfo Return type: GlyphInfo Description: Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found Param[1]: font (type: Font) Param[2]: codepoint (type: int) -Function 433: GetGlyphAtlasRec() (2 input parameters) +Function 437: GetGlyphAtlasRec() (2 input parameters) Name: GetGlyphAtlasRec Return type: Rectangle Description: Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found Param[1]: font (type: Font) Param[2]: codepoint (type: int) -Function 434: LoadUTF8() (2 input parameters) +Function 438: LoadUTF8() (2 input parameters) Name: LoadUTF8 Return type: char * Description: Load UTF-8 text encoded from codepoints array Param[1]: codepoints (type: const int *) Param[2]: length (type: int) -Function 435: UnloadUTF8() (1 input parameters) +Function 439: UnloadUTF8() (1 input parameters) Name: UnloadUTF8 Return type: void Description: Unload UTF-8 text encoded from codepoints array Param[1]: text (type: char *) -Function 436: LoadCodepoints() (2 input parameters) +Function 440: LoadCodepoints() (2 input parameters) Name: LoadCodepoints Return type: int * Description: Load all codepoints from a UTF-8 text string, codepoints count returned by parameter Param[1]: text (type: const char *) Param[2]: count (type: int *) -Function 437: UnloadCodepoints() (1 input parameters) +Function 441: UnloadCodepoints() (1 input parameters) Name: UnloadCodepoints Return type: void Description: Unload codepoints data from memory Param[1]: codepoints (type: int *) -Function 438: GetCodepointCount() (1 input parameters) +Function 442: GetCodepointCount() (1 input parameters) Name: GetCodepointCount Return type: int Description: Get total number of codepoints in a UTF-8 encoded string Param[1]: text (type: const char *) -Function 439: GetCodepoint() (2 input parameters) +Function 443: GetCodepoint() (2 input parameters) Name: GetCodepoint Return type: int Description: Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure Param[1]: text (type: const char *) Param[2]: codepointSize (type: int *) -Function 440: GetCodepointNext() (2 input parameters) +Function 444: GetCodepointNext() (2 input parameters) Name: GetCodepointNext Return type: int Description: Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure Param[1]: text (type: const char *) Param[2]: codepointSize (type: int *) -Function 441: GetCodepointPrevious() (2 input parameters) +Function 445: GetCodepointPrevious() (2 input parameters) Name: GetCodepointPrevious Return type: int Description: Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure Param[1]: text (type: const char *) Param[2]: codepointSize (type: int *) -Function 442: CodepointToUTF8() (2 input parameters) +Function 446: CodepointToUTF8() (2 input parameters) Name: CodepointToUTF8 Return type: const char * Description: Encode one codepoint into UTF-8 byte array (array length returned as parameter) Param[1]: codepoint (type: int) Param[2]: utf8Size (type: int *) -Function 443: LoadTextLines() (2 input parameters) +Function 447: LoadTextLines() (2 input parameters) Name: LoadTextLines Return type: char ** Description: Load text as separate lines ('\n') Param[1]: text (type: const char *) Param[2]: count (type: int *) -Function 444: UnloadTextLines() (2 input parameters) +Function 448: UnloadTextLines() (2 input parameters) Name: UnloadTextLines Return type: void Description: Unload text lines Param[1]: text (type: char **) Param[2]: lineCount (type: int) -Function 445: TextCopy() (2 input parameters) +Function 449: TextCopy() (2 input parameters) Name: TextCopy Return type: int Description: Copy one string to another, returns bytes copied Param[1]: dst (type: char *) Param[2]: src (type: const char *) -Function 446: TextIsEqual() (2 input parameters) +Function 450: TextIsEqual() (2 input parameters) Name: TextIsEqual Return type: bool Description: Check if two text strings are equal Param[1]: text1 (type: const char *) Param[2]: text2 (type: const char *) -Function 447: TextLength() (1 input parameters) +Function 451: TextLength() (1 input parameters) Name: TextLength Return type: unsigned int Description: Get text length, checks for '\0' ending Param[1]: text (type: const char *) -Function 448: TextFormat() (2 input parameters) +Function 452: TextFormat() (2 input parameters) Name: TextFormat Return type: const char * Description: Text formatting with variables (sprintf() style) Param[1]: text (type: const char *) Param[2]: args (type: ...) -Function 449: TextSubtext() (3 input parameters) +Function 453: TextSubtext() (3 input parameters) Name: TextSubtext Return type: const char * Description: Get a piece of a text string Param[1]: text (type: const char *) Param[2]: position (type: int) Param[3]: length (type: int) -Function 450: TextRemoveSpaces() (1 input parameters) +Function 454: TextRemoveSpaces() (1 input parameters) Name: TextRemoveSpaces Return type: const char * Description: Remove text spaces, concat words Param[1]: text (type: const char *) -Function 451: GetTextBetween() (3 input parameters) +Function 455: GetTextBetween() (3 input parameters) Name: GetTextBetween Return type: char * Description: Get text between two strings Param[1]: text (type: const char *) Param[2]: begin (type: const char *) Param[3]: end (type: const char *) -Function 452: TextReplace() (3 input parameters) +Function 456: TextReplace() (3 input parameters) Name: TextReplace Return type: char * Description: Replace text string with new string Param[1]: text (type: const char *) Param[2]: search (type: const char *) Param[3]: replacement (type: const char *) -Function 453: TextReplaceAlloc() (3 input parameters) +Function 457: TextReplaceAlloc() (3 input parameters) Name: TextReplaceAlloc Return type: char * Description: Replace text string with new string, memory must be MemFree() Param[1]: text (type: const char *) Param[2]: search (type: const char *) Param[3]: replacement (type: const char *) -Function 454: TextReplaceBetween() (4 input parameters) +Function 458: TextReplaceBetween() (4 input parameters) Name: TextReplaceBetween Return type: char * Description: Replace text between two specific strings @@ -3889,7 +3931,7 @@ Function 454: TextReplaceBetween() (4 input parameters) Param[2]: begin (type: const char *) Param[3]: end (type: const char *) Param[4]: replacement (type: const char *) -Function 455: TextReplaceBetweenAlloc() (4 input parameters) +Function 459: TextReplaceBetweenAlloc() (4 input parameters) Name: TextReplaceBetweenAlloc Return type: char * Description: Replace text between two specific strings, memory must be MemFree() @@ -3897,96 +3939,96 @@ Function 455: TextReplaceBetweenAlloc() (4 input parameters) Param[2]: begin (type: const char *) Param[3]: end (type: const char *) Param[4]: replacement (type: const char *) -Function 456: TextInsert() (3 input parameters) +Function 460: TextInsert() (3 input parameters) Name: TextInsert Return type: char * Description: Insert text in a defined byte position Param[1]: text (type: const char *) Param[2]: insert (type: const char *) Param[3]: position (type: int) -Function 457: TextInsertAlloc() (3 input parameters) +Function 461: TextInsertAlloc() (3 input parameters) Name: TextInsertAlloc Return type: char * Description: Insert text in a defined byte position, memory must be MemFree() Param[1]: text (type: const char *) Param[2]: insert (type: const char *) Param[3]: position (type: int) -Function 458: TextJoin() (3 input parameters) +Function 462: TextJoin() (3 input parameters) Name: TextJoin Return type: char * Description: Join text strings with delimiter Param[1]: textList (type: char **) Param[2]: count (type: int) Param[3]: delimiter (type: const char *) -Function 459: TextSplit() (3 input parameters) +Function 463: TextSplit() (3 input parameters) Name: TextSplit Return type: char ** Description: Split text into multiple strings, using MAX_TEXTSPLIT_COUNT static strings Param[1]: text (type: const char *) Param[2]: delimiter (type: char) Param[3]: count (type: int *) -Function 460: TextAppend() (3 input parameters) +Function 464: TextAppend() (3 input parameters) Name: TextAppend Return type: void Description: Append text at specific position and move cursor Param[1]: text (type: char *) Param[2]: append (type: const char *) Param[3]: position (type: int *) -Function 461: TextFindIndex() (2 input parameters) +Function 465: TextFindIndex() (2 input parameters) Name: TextFindIndex Return type: int Description: Find first text occurrence within a string, -1 if not found Param[1]: text (type: const char *) Param[2]: search (type: const char *) -Function 462: TextToUpper() (1 input parameters) +Function 466: TextToUpper() (1 input parameters) Name: TextToUpper Return type: char * Description: Get upper case version of provided string Param[1]: text (type: const char *) -Function 463: TextToLower() (1 input parameters) +Function 467: TextToLower() (1 input parameters) Name: TextToLower Return type: char * Description: Get lower case version of provided string Param[1]: text (type: const char *) -Function 464: TextToPascal() (1 input parameters) +Function 468: TextToPascal() (1 input parameters) Name: TextToPascal Return type: char * Description: Get Pascal case notation version of provided string Param[1]: text (type: const char *) -Function 465: TextToSnake() (1 input parameters) +Function 469: TextToSnake() (1 input parameters) Name: TextToSnake Return type: char * Description: Get Snake case notation version of provided string Param[1]: text (type: const char *) -Function 466: TextToCamel() (1 input parameters) +Function 470: TextToCamel() (1 input parameters) Name: TextToCamel Return type: char * Description: Get Camel case notation version of provided string Param[1]: text (type: const char *) -Function 467: TextToInteger() (1 input parameters) +Function 471: TextToInteger() (1 input parameters) Name: TextToInteger Return type: int Description: Get integer value from text Param[1]: text (type: const char *) -Function 468: TextToFloat() (1 input parameters) +Function 472: TextToFloat() (1 input parameters) Name: TextToFloat Return type: float Description: Get float value from text Param[1]: text (type: const char *) -Function 469: DrawLine3D() (3 input parameters) +Function 473: DrawLine3D() (3 input parameters) Name: DrawLine3D Return type: void Description: Draw a line in 3D world space Param[1]: startPos (type: Vector3) Param[2]: endPos (type: Vector3) Param[3]: color (type: Color) -Function 470: DrawPoint3D() (2 input parameters) +Function 474: DrawPoint3D() (2 input parameters) Name: DrawPoint3D Return type: void Description: Draw a point in 3D space, actually a small line Param[1]: position (type: Vector3) Param[2]: color (type: Color) -Function 471: DrawCircle3D() (5 input parameters) +Function 475: DrawCircle3D() (5 input parameters) Name: DrawCircle3D Return type: void Description: Draw a circle in 3D world space @@ -3995,7 +4037,7 @@ Function 471: DrawCircle3D() (5 input parameters) Param[3]: rotationAxis (type: Vector3) Param[4]: rotationAngle (type: float) Param[5]: color (type: Color) -Function 472: DrawTriangle3D() (4 input parameters) +Function 476: DrawTriangle3D() (4 input parameters) Name: DrawTriangle3D Return type: void Description: Draw a color-filled triangle, counter-clockwise vertex order @@ -4003,14 +4045,14 @@ Function 472: DrawTriangle3D() (4 input parameters) Param[2]: v2 (type: Vector3) Param[3]: v3 (type: Vector3) Param[4]: color (type: Color) -Function 473: DrawTriangleStrip3D() (3 input parameters) +Function 477: DrawTriangleStrip3D() (3 input parameters) Name: DrawTriangleStrip3D Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: const Vector3 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 474: DrawCube() (5 input parameters) +Function 478: DrawCube() (5 input parameters) Name: DrawCube Return type: void Description: Draw cube @@ -4019,14 +4061,14 @@ Function 474: DrawCube() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 475: DrawCubeV() (3 input parameters) +Function 479: DrawCubeV() (3 input parameters) Name: DrawCubeV Return type: void Description: Draw cube (Vector version) Param[1]: position (type: Vector3) Param[2]: size (type: Vector3) Param[3]: color (type: Color) -Function 476: DrawCubeWires() (5 input parameters) +Function 480: DrawCubeWires() (5 input parameters) Name: DrawCubeWires Return type: void Description: Draw cube wires @@ -4035,21 +4077,21 @@ Function 476: DrawCubeWires() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 477: DrawCubeWiresV() (3 input parameters) +Function 481: DrawCubeWiresV() (3 input parameters) Name: DrawCubeWiresV Return type: void Description: Draw cube wires (Vector version) Param[1]: position (type: Vector3) Param[2]: size (type: Vector3) Param[3]: color (type: Color) -Function 478: DrawSphere() (3 input parameters) +Function 482: DrawSphere() (3 input parameters) Name: DrawSphere Return type: void Description: Draw sphere Param[1]: centerPos (type: Vector3) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 479: DrawSphereEx() (5 input parameters) +Function 483: DrawSphereEx() (5 input parameters) Name: DrawSphereEx Return type: void Description: Draw sphere with defined rings and slices @@ -4058,7 +4100,7 @@ Function 479: DrawSphereEx() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 480: DrawSphereWires() (5 input parameters) +Function 484: DrawSphereWires() (5 input parameters) Name: DrawSphereWires Return type: void Description: Draw sphere wires @@ -4067,7 +4109,7 @@ Function 480: DrawSphereWires() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 481: DrawCylinder() (6 input parameters) +Function 485: DrawCylinder() (6 input parameters) Name: DrawCylinder Return type: void Description: Draw a cylinder/cone @@ -4077,7 +4119,7 @@ Function 481: DrawCylinder() (6 input parameters) Param[4]: height (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 482: DrawCylinderEx() (6 input parameters) +Function 486: DrawCylinderEx() (6 input parameters) Name: DrawCylinderEx Return type: void Description: Draw a cylinder with base at startPos and top at endPos @@ -4087,7 +4129,7 @@ Function 482: DrawCylinderEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 483: DrawCylinderWires() (6 input parameters) +Function 487: DrawCylinderWires() (6 input parameters) Name: DrawCylinderWires Return type: void Description: Draw a cylinder/cone wires @@ -4097,7 +4139,7 @@ Function 483: DrawCylinderWires() (6 input parameters) Param[4]: height (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 484: DrawCylinderWiresEx() (6 input parameters) +Function 488: DrawCylinderWiresEx() (6 input parameters) Name: DrawCylinderWiresEx Return type: void Description: Draw a cylinder wires with base at startPos and top at endPos @@ -4107,7 +4149,7 @@ Function 484: DrawCylinderWiresEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 485: DrawCapsule() (6 input parameters) +Function 489: DrawCapsule() (6 input parameters) Name: DrawCapsule Return type: void Description: Draw a capsule with the center of its sphere caps at startPos and endPos @@ -4117,7 +4159,7 @@ Function 485: DrawCapsule() (6 input parameters) Param[4]: rings (type: int) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 486: DrawCapsuleWires() (6 input parameters) +Function 490: DrawCapsuleWires() (6 input parameters) Name: DrawCapsuleWires Return type: void Description: Draw capsule wireframe with the center of its sphere caps at startPos and endPos @@ -4127,51 +4169,51 @@ Function 486: DrawCapsuleWires() (6 input parameters) Param[4]: rings (type: int) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 487: DrawPlane() (3 input parameters) +Function 491: DrawPlane() (3 input parameters) Name: DrawPlane Return type: void Description: Draw a plane XZ Param[1]: centerPos (type: Vector3) Param[2]: size (type: Vector2) Param[3]: color (type: Color) -Function 488: DrawRay() (2 input parameters) +Function 492: DrawRay() (2 input parameters) Name: DrawRay Return type: void Description: Draw a ray line Param[1]: ray (type: Ray) Param[2]: color (type: Color) -Function 489: DrawGrid() (2 input parameters) +Function 493: DrawGrid() (2 input parameters) Name: DrawGrid Return type: void Description: Draw a grid (centered at (0, 0, 0)) Param[1]: slices (type: int) Param[2]: spacing (type: float) -Function 490: LoadModel() (1 input parameters) +Function 494: LoadModel() (1 input parameters) Name: LoadModel Return type: Model Description: Load model from files (meshes and materials) Param[1]: fileName (type: const char *) -Function 491: LoadModelFromMesh() (1 input parameters) +Function 495: LoadModelFromMesh() (1 input parameters) Name: LoadModelFromMesh Return type: Model Description: Load model from generated mesh (default material) Param[1]: mesh (type: Mesh) -Function 492: IsModelValid() (1 input parameters) +Function 496: IsModelValid() (1 input parameters) Name: IsModelValid Return type: bool Description: Check if model is valid (loaded in GPU, VAO/VBOs) Param[1]: model (type: Model) -Function 493: UnloadModel() (1 input parameters) +Function 497: UnloadModel() (1 input parameters) Name: UnloadModel Return type: void Description: Unload model (including meshes) from memory (RAM and/or VRAM) Param[1]: model (type: Model) -Function 494: GetModelBoundingBox() (1 input parameters) +Function 498: GetModelBoundingBox() (1 input parameters) Name: GetModelBoundingBox Return type: BoundingBox Description: Compute model bounding box limits (considers all meshes) Param[1]: model (type: Model) -Function 495: DrawModel() (4 input parameters) +Function 499: DrawModel() (4 input parameters) Name: DrawModel Return type: void Description: Draw a model (with texture if set) @@ -4179,7 +4221,7 @@ Function 495: DrawModel() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 496: DrawModelEx() (6 input parameters) +Function 500: DrawModelEx() (6 input parameters) Name: DrawModelEx Return type: void Description: Draw a model with custom transform @@ -4189,7 +4231,7 @@ Function 496: DrawModelEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 497: DrawModelWires() (4 input parameters) +Function 501: DrawModelWires() (4 input parameters) Name: DrawModelWires Return type: void Description: Draw a model wires (with texture if set) @@ -4197,7 +4239,7 @@ Function 497: DrawModelWires() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 498: DrawModelWiresEx() (6 input parameters) +Function 502: DrawModelWiresEx() (6 input parameters) Name: DrawModelWiresEx Return type: void Description: Draw a model wires with custom transform @@ -4207,13 +4249,13 @@ Function 498: DrawModelWiresEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 499: DrawBoundingBox() (2 input parameters) +Function 503: DrawBoundingBox() (2 input parameters) Name: DrawBoundingBox Return type: void Description: Draw bounding box (wires) Param[1]: box (type: BoundingBox) Param[2]: color (type: Color) -Function 500: DrawBillboard() (5 input parameters) +Function 504: DrawBillboard() (5 input parameters) Name: DrawBillboard Return type: void Description: Draw a billboard texture @@ -4222,7 +4264,7 @@ Function 500: DrawBillboard() (5 input parameters) Param[3]: position (type: Vector3) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 501: DrawBillboardRec() (6 input parameters) +Function 505: DrawBillboardRec() (6 input parameters) Name: DrawBillboardRec Return type: void Description: Draw a billboard texture defined by rectangle @@ -4232,7 +4274,7 @@ Function 501: DrawBillboardRec() (6 input parameters) Param[4]: position (type: Vector3) Param[5]: size (type: Vector2) Param[6]: tint (type: Color) -Function 502: DrawBillboardPro() (9 input parameters) +Function 506: DrawBillboardPro() (9 input parameters) Name: DrawBillboardPro Return type: void Description: Draw a billboard texture defined by source rectangle with scaling and rotation @@ -4245,13 +4287,13 @@ Function 502: DrawBillboardPro() (9 input parameters) Param[7]: origin (type: Vector2) Param[8]: rotation (type: float) Param[9]: tint (type: Color) -Function 503: UploadMesh() (2 input parameters) +Function 507: UploadMesh() (2 input parameters) Name: UploadMesh Return type: void Description: Upload mesh vertex data in GPU and provide VAO/VBO ids Param[1]: mesh (type: Mesh *) Param[2]: dynamic (type: bool) -Function 504: UpdateMeshBuffer() (5 input parameters) +Function 508: UpdateMeshBuffer() (5 input parameters) Name: UpdateMeshBuffer Return type: void Description: Update mesh vertex data in GPU for a specific buffer index @@ -4260,19 +4302,19 @@ Function 504: UpdateMeshBuffer() (5 input parameters) Param[3]: data (type: const void *) Param[4]: dataSize (type: int) Param[5]: offset (type: int) -Function 505: UnloadMesh() (1 input parameters) +Function 509: UnloadMesh() (1 input parameters) Name: UnloadMesh Return type: void Description: Unload mesh data from CPU and GPU Param[1]: mesh (type: Mesh) -Function 506: DrawMesh() (3 input parameters) +Function 510: DrawMesh() (3 input parameters) Name: DrawMesh Return type: void Description: Draw a 3d mesh with material and transform Param[1]: mesh (type: Mesh) Param[2]: material (type: Material) Param[3]: transform (type: Matrix) -Function 507: DrawMeshInstanced() (4 input parameters) +Function 511: DrawMeshInstanced() (4 input parameters) Name: DrawMeshInstanced Return type: void Description: Draw multiple mesh instances with material and different transforms @@ -4280,35 +4322,35 @@ Function 507: DrawMeshInstanced() (4 input parameters) Param[2]: material (type: Material) Param[3]: transforms (type: const Matrix *) Param[4]: instances (type: int) -Function 508: GetMeshBoundingBox() (1 input parameters) +Function 512: GetMeshBoundingBox() (1 input parameters) Name: GetMeshBoundingBox Return type: BoundingBox Description: Compute mesh bounding box limits Param[1]: mesh (type: Mesh) -Function 509: GenMeshTangents() (1 input parameters) +Function 513: GenMeshTangents() (1 input parameters) Name: GenMeshTangents Return type: void Description: Compute mesh tangents Param[1]: mesh (type: Mesh *) -Function 510: ExportMesh() (2 input parameters) +Function 514: ExportMesh() (2 input parameters) Name: ExportMesh Return type: bool Description: Export mesh data to file, returns true on success Param[1]: mesh (type: Mesh) Param[2]: fileName (type: const char *) -Function 511: ExportMeshAsCode() (2 input parameters) +Function 515: ExportMeshAsCode() (2 input parameters) Name: ExportMeshAsCode Return type: bool Description: Export mesh as code file (.h) defining multiple arrays of vertex attributes Param[1]: mesh (type: Mesh) Param[2]: fileName (type: const char *) -Function 512: GenMeshPoly() (2 input parameters) +Function 516: GenMeshPoly() (2 input parameters) Name: GenMeshPoly Return type: Mesh Description: Generate polygonal mesh Param[1]: sides (type: int) Param[2]: radius (type: float) -Function 513: GenMeshPlane() (4 input parameters) +Function 517: GenMeshPlane() (4 input parameters) Name: GenMeshPlane Return type: Mesh Description: Generate plane mesh (with subdivisions) @@ -4316,42 +4358,42 @@ Function 513: GenMeshPlane() (4 input parameters) Param[2]: length (type: float) Param[3]: resX (type: int) Param[4]: resZ (type: int) -Function 514: GenMeshCube() (3 input parameters) +Function 518: GenMeshCube() (3 input parameters) Name: GenMeshCube Return type: Mesh Description: Generate cuboid mesh Param[1]: width (type: float) Param[2]: height (type: float) Param[3]: length (type: float) -Function 515: GenMeshSphere() (3 input parameters) +Function 519: GenMeshSphere() (3 input parameters) Name: GenMeshSphere Return type: Mesh Description: Generate sphere mesh (standard sphere) Param[1]: radius (type: float) Param[2]: rings (type: int) Param[3]: slices (type: int) -Function 516: GenMeshHemiSphere() (3 input parameters) +Function 520: GenMeshHemiSphere() (3 input parameters) Name: GenMeshHemiSphere Return type: Mesh Description: Generate half-sphere mesh (no bottom cap) Param[1]: radius (type: float) Param[2]: rings (type: int) Param[3]: slices (type: int) -Function 517: GenMeshCylinder() (3 input parameters) +Function 521: GenMeshCylinder() (3 input parameters) Name: GenMeshCylinder Return type: Mesh Description: Generate cylinder mesh Param[1]: radius (type: float) Param[2]: height (type: float) Param[3]: slices (type: int) -Function 518: GenMeshCone() (3 input parameters) +Function 522: GenMeshCone() (3 input parameters) Name: GenMeshCone Return type: Mesh Description: Generate cone/pyramid mesh Param[1]: radius (type: float) Param[2]: height (type: float) Param[3]: slices (type: int) -Function 519: GenMeshTorus() (4 input parameters) +Function 523: GenMeshTorus() (4 input parameters) Name: GenMeshTorus Return type: Mesh Description: Generate torus mesh @@ -4359,7 +4401,7 @@ Function 519: GenMeshTorus() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 520: GenMeshKnot() (4 input parameters) +Function 524: GenMeshKnot() (4 input parameters) Name: GenMeshKnot Return type: Mesh Description: Generate trefoil knot mesh @@ -4367,67 +4409,67 @@ Function 520: GenMeshKnot() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 521: GenMeshHeightmap() (2 input parameters) +Function 525: GenMeshHeightmap() (2 input parameters) Name: GenMeshHeightmap Return type: Mesh Description: Generate heightmap mesh from image data Param[1]: heightmap (type: Image) Param[2]: size (type: Vector3) -Function 522: GenMeshCubicmap() (2 input parameters) +Function 526: GenMeshCubicmap() (2 input parameters) Name: GenMeshCubicmap Return type: Mesh Description: Generate cubes-based map mesh from image data Param[1]: cubicmap (type: Image) Param[2]: cubeSize (type: Vector3) -Function 523: LoadMaterials() (2 input parameters) +Function 527: LoadMaterials() (2 input parameters) Name: LoadMaterials Return type: Material * Description: Load materials from model file Param[1]: fileName (type: const char *) Param[2]: materialCount (type: int *) -Function 524: LoadMaterialDefault() (0 input parameters) +Function 528: LoadMaterialDefault() (0 input parameters) Name: LoadMaterialDefault Return type: Material Description: Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) No input parameters -Function 525: IsMaterialValid() (1 input parameters) +Function 529: IsMaterialValid() (1 input parameters) Name: IsMaterialValid Return type: bool Description: Check if material is valid (shader assigned, map textures loaded in GPU) Param[1]: material (type: Material) -Function 526: UnloadMaterial() (1 input parameters) +Function 530: UnloadMaterial() (1 input parameters) Name: UnloadMaterial Return type: void Description: Unload material from GPU memory (VRAM) Param[1]: material (type: Material) -Function 527: SetMaterialTexture() (3 input parameters) +Function 531: SetMaterialTexture() (3 input parameters) Name: SetMaterialTexture Return type: void Description: Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...) Param[1]: material (type: Material *) Param[2]: mapType (type: int) Param[3]: texture (type: Texture2D) -Function 528: SetModelMeshMaterial() (3 input parameters) +Function 532: SetModelMeshMaterial() (3 input parameters) Name: SetModelMeshMaterial Return type: void Description: Set material for a mesh Param[1]: model (type: Model *) Param[2]: meshId (type: int) Param[3]: materialId (type: int) -Function 529: LoadModelAnimations() (2 input parameters) +Function 533: LoadModelAnimations() (2 input parameters) Name: LoadModelAnimations Return type: ModelAnimation * Description: Load model animations from file Param[1]: fileName (type: const char *) Param[2]: animCount (type: int *) -Function 530: UpdateModelAnimation() (3 input parameters) +Function 534: UpdateModelAnimation() (3 input parameters) Name: UpdateModelAnimation Return type: void Description: Update model animation pose (vertex buffers and bone matrices) Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) Param[3]: frame (type: float) -Function 531: UpdateModelAnimationEx() (6 input parameters) +Function 535: UpdateModelAnimationEx() (6 input parameters) Name: UpdateModelAnimationEx Return type: void Description: Update model animation pose, blending two animations @@ -4437,19 +4479,19 @@ Function 531: UpdateModelAnimationEx() (6 input parameters) Param[4]: animB (type: ModelAnimation) Param[5]: frameB (type: float) Param[6]: blend (type: float) -Function 532: UnloadModelAnimations() (2 input parameters) +Function 536: UnloadModelAnimations() (2 input parameters) Name: UnloadModelAnimations Return type: void Description: Unload animation array data Param[1]: animations (type: ModelAnimation *) Param[2]: animCount (type: int) -Function 533: IsModelAnimationValid() (2 input parameters) +Function 537: IsModelAnimationValid() (2 input parameters) Name: IsModelAnimationValid Return type: bool Description: Check model animation skeleton match Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) -Function 534: CheckCollisionSpheres() (4 input parameters) +Function 538: CheckCollisionSpheres() (4 input parameters) Name: CheckCollisionSpheres Return type: bool Description: Check collision between two spheres @@ -4457,40 +4499,40 @@ Function 534: CheckCollisionSpheres() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector3) Param[4]: radius2 (type: float) -Function 535: CheckCollisionBoxes() (2 input parameters) +Function 539: CheckCollisionBoxes() (2 input parameters) Name: CheckCollisionBoxes Return type: bool Description: Check collision between two bounding boxes Param[1]: box1 (type: BoundingBox) Param[2]: box2 (type: BoundingBox) -Function 536: CheckCollisionBoxSphere() (3 input parameters) +Function 540: CheckCollisionBoxSphere() (3 input parameters) Name: CheckCollisionBoxSphere Return type: bool Description: Check collision between box and sphere Param[1]: box (type: BoundingBox) Param[2]: center (type: Vector3) Param[3]: radius (type: float) -Function 537: GetRayCollisionSphere() (3 input parameters) +Function 541: GetRayCollisionSphere() (3 input parameters) Name: GetRayCollisionSphere Return type: RayCollision Description: Get collision info between ray and sphere Param[1]: ray (type: Ray) Param[2]: center (type: Vector3) Param[3]: radius (type: float) -Function 538: GetRayCollisionBox() (2 input parameters) +Function 542: GetRayCollisionBox() (2 input parameters) Name: GetRayCollisionBox Return type: RayCollision Description: Get collision info between ray and box Param[1]: ray (type: Ray) Param[2]: box (type: BoundingBox) -Function 539: GetRayCollisionMesh() (3 input parameters) +Function 543: GetRayCollisionMesh() (3 input parameters) Name: GetRayCollisionMesh Return type: RayCollision Description: Get collision info between ray and mesh Param[1]: ray (type: Ray) Param[2]: mesh (type: Mesh) Param[3]: transform (type: Matrix) -Function 540: GetRayCollisionTriangle() (4 input parameters) +Function 544: GetRayCollisionTriangle() (4 input parameters) Name: GetRayCollisionTriangle Return type: RayCollision Description: Get collision info between ray and triangle @@ -4498,7 +4540,7 @@ Function 540: GetRayCollisionTriangle() (4 input parameters) Param[2]: p1 (type: Vector3) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) -Function 541: GetRayCollisionQuad() (5 input parameters) +Function 545: GetRayCollisionQuad() (5 input parameters) Name: GetRayCollisionQuad Return type: RayCollision Description: Get collision info between ray and quad @@ -4507,158 +4549,158 @@ Function 541: GetRayCollisionQuad() (5 input parameters) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) Param[5]: p4 (type: Vector3) -Function 542: InitAudioDevice() (0 input parameters) +Function 546: InitAudioDevice() (0 input parameters) Name: InitAudioDevice Return type: void Description: Initialize audio device and context No input parameters -Function 543: CloseAudioDevice() (0 input parameters) +Function 547: CloseAudioDevice() (0 input parameters) Name: CloseAudioDevice Return type: void Description: Close the audio device and context No input parameters -Function 544: IsAudioDeviceReady() (0 input parameters) +Function 548: IsAudioDeviceReady() (0 input parameters) Name: IsAudioDeviceReady Return type: bool Description: Check if audio device has been initialized successfully No input parameters -Function 545: SetMasterVolume() (1 input parameters) +Function 549: SetMasterVolume() (1 input parameters) Name: SetMasterVolume Return type: void Description: Set master volume (listener) Param[1]: volume (type: float) -Function 546: GetMasterVolume() (0 input parameters) +Function 550: GetMasterVolume() (0 input parameters) Name: GetMasterVolume Return type: float Description: Get master volume (listener) No input parameters -Function 547: LoadWave() (1 input parameters) +Function 551: LoadWave() (1 input parameters) Name: LoadWave Return type: Wave Description: Load wave data from file Param[1]: fileName (type: const char *) -Function 548: LoadWaveFromMemory() (3 input parameters) +Function 552: LoadWaveFromMemory() (3 input parameters) Name: LoadWaveFromMemory Return type: Wave Description: Load wave from memory buffer, fileType refers to extension: i.e. '.wav' Param[1]: fileType (type: const char *) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 549: IsWaveValid() (1 input parameters) +Function 553: IsWaveValid() (1 input parameters) Name: IsWaveValid Return type: bool Description: Check if wave data is valid (data loaded and parameters) Param[1]: wave (type: Wave) -Function 550: LoadSound() (1 input parameters) +Function 554: LoadSound() (1 input parameters) Name: LoadSound Return type: Sound Description: Load sound from file Param[1]: fileName (type: const char *) -Function 551: LoadSoundFromWave() (1 input parameters) +Function 555: LoadSoundFromWave() (1 input parameters) Name: LoadSoundFromWave Return type: Sound Description: Load sound from wave data Param[1]: wave (type: Wave) -Function 552: LoadSoundAlias() (1 input parameters) +Function 556: LoadSoundAlias() (1 input parameters) Name: LoadSoundAlias Return type: Sound Description: Load sound alias, new sound that shares the same sample data as the source sound, does not own the sound data Param[1]: source (type: Sound) -Function 553: IsSoundValid() (1 input parameters) +Function 557: IsSoundValid() (1 input parameters) Name: IsSoundValid Return type: bool Description: Check if sound is valid (data loaded and buffers initialized) Param[1]: sound (type: Sound) -Function 554: UpdateSound() (3 input parameters) +Function 558: UpdateSound() (3 input parameters) Name: UpdateSound Return type: void Description: Update sound buffer with new data (default data format: 32 bit float, stereo) Param[1]: sound (type: Sound) Param[2]: data (type: const void *) Param[3]: frameCount (type: int) -Function 555: UnloadWave() (1 input parameters) +Function 559: UnloadWave() (1 input parameters) Name: UnloadWave Return type: void Description: Unload wave data Param[1]: wave (type: Wave) -Function 556: UnloadSound() (1 input parameters) +Function 560: UnloadSound() (1 input parameters) Name: UnloadSound Return type: void Description: Unload sound Param[1]: sound (type: Sound) -Function 557: UnloadSoundAlias() (1 input parameters) +Function 561: UnloadSoundAlias() (1 input parameters) Name: UnloadSoundAlias Return type: void Description: Unload sound alias (does not deallocate sample data) Param[1]: alias (type: Sound) -Function 558: ExportWave() (2 input parameters) +Function 562: ExportWave() (2 input parameters) Name: ExportWave Return type: bool Description: Export wave data to file, returns true on success Param[1]: wave (type: Wave) Param[2]: fileName (type: const char *) -Function 559: ExportWaveAsCode() (2 input parameters) +Function 563: ExportWaveAsCode() (2 input parameters) Name: ExportWaveAsCode Return type: bool Description: Export wave sample data to code (.h), returns true on success Param[1]: wave (type: Wave) Param[2]: fileName (type: const char *) -Function 560: PlaySound() (1 input parameters) +Function 564: PlaySound() (1 input parameters) Name: PlaySound Return type: void Description: Play a sound Param[1]: sound (type: Sound) -Function 561: StopSound() (1 input parameters) +Function 565: StopSound() (1 input parameters) Name: StopSound Return type: void Description: Stop playing a sound Param[1]: sound (type: Sound) -Function 562: PauseSound() (1 input parameters) +Function 566: PauseSound() (1 input parameters) Name: PauseSound Return type: void Description: Pause a sound Param[1]: sound (type: Sound) -Function 563: ResumeSound() (1 input parameters) +Function 567: ResumeSound() (1 input parameters) Name: ResumeSound Return type: void Description: Resume a paused sound Param[1]: sound (type: Sound) -Function 564: IsSoundPlaying() (1 input parameters) +Function 568: IsSoundPlaying() (1 input parameters) Name: IsSoundPlaying Return type: bool Description: Check if sound is currently playing Param[1]: sound (type: Sound) -Function 565: SetSoundVolume() (2 input parameters) +Function 569: SetSoundVolume() (2 input parameters) Name: SetSoundVolume Return type: void Description: Set volume for a sound (1.0 is max level) Param[1]: sound (type: Sound) Param[2]: volume (type: float) -Function 566: SetSoundPitch() (2 input parameters) +Function 570: SetSoundPitch() (2 input parameters) Name: SetSoundPitch Return type: void Description: Set pitch for a sound (1.0 is base level) Param[1]: sound (type: Sound) Param[2]: pitch (type: float) -Function 567: SetSoundPan() (2 input parameters) +Function 571: SetSoundPan() (2 input parameters) Name: SetSoundPan Return type: void Description: Set pan for a sound (-1.0 left, 0.0 center, 1.0 right) Param[1]: sound (type: Sound) Param[2]: pan (type: float) -Function 568: WaveCopy() (1 input parameters) +Function 572: WaveCopy() (1 input parameters) Name: WaveCopy Return type: Wave Description: Copy a wave to a new wave Param[1]: wave (type: Wave) -Function 569: WaveCrop() (3 input parameters) +Function 573: WaveCrop() (3 input parameters) Name: WaveCrop Return type: void Description: Crop a wave to defined frames range Param[1]: wave (type: Wave *) Param[2]: initFrame (type: int) Param[3]: finalFrame (type: int) -Function 570: WaveFormat() (4 input parameters) +Function 574: WaveFormat() (4 input parameters) Name: WaveFormat Return type: void Description: Convert wave data to desired format @@ -4666,203 +4708,203 @@ Function 570: WaveFormat() (4 input parameters) Param[2]: sampleRate (type: int) Param[3]: sampleSize (type: int) Param[4]: channels (type: int) -Function 571: LoadWaveSamples() (1 input parameters) +Function 575: LoadWaveSamples() (1 input parameters) Name: LoadWaveSamples Return type: float * Description: Load samples data from wave as a 32bit float data array Param[1]: wave (type: Wave) -Function 572: UnloadWaveSamples() (1 input parameters) +Function 576: UnloadWaveSamples() (1 input parameters) Name: UnloadWaveSamples Return type: void Description: Unload samples data loaded with LoadWaveSamples() Param[1]: samples (type: float *) -Function 573: LoadMusicStream() (1 input parameters) +Function 577: LoadMusicStream() (1 input parameters) Name: LoadMusicStream Return type: Music Description: Load music stream from file Param[1]: fileName (type: const char *) -Function 574: LoadMusicStreamFromMemory() (3 input parameters) +Function 578: LoadMusicStreamFromMemory() (3 input parameters) Name: LoadMusicStreamFromMemory Return type: Music Description: Load music stream from data Param[1]: fileType (type: const char *) Param[2]: data (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 575: IsMusicValid() (1 input parameters) +Function 579: IsMusicValid() (1 input parameters) Name: IsMusicValid Return type: bool Description: Check if music stream is valid (context and buffers initialized) Param[1]: music (type: Music) -Function 576: UnloadMusicStream() (1 input parameters) +Function 580: UnloadMusicStream() (1 input parameters) Name: UnloadMusicStream Return type: void Description: Unload music stream Param[1]: music (type: Music) -Function 577: PlayMusicStream() (1 input parameters) +Function 581: PlayMusicStream() (1 input parameters) Name: PlayMusicStream Return type: void Description: Start music playing Param[1]: music (type: Music) -Function 578: IsMusicStreamPlaying() (1 input parameters) +Function 582: IsMusicStreamPlaying() (1 input parameters) Name: IsMusicStreamPlaying Return type: bool Description: Check if music is playing Param[1]: music (type: Music) -Function 579: UpdateMusicStream() (1 input parameters) +Function 583: UpdateMusicStream() (1 input parameters) Name: UpdateMusicStream Return type: void Description: Update buffers for music streaming Param[1]: music (type: Music) -Function 580: StopMusicStream() (1 input parameters) +Function 584: StopMusicStream() (1 input parameters) Name: StopMusicStream Return type: void Description: Stop music playing Param[1]: music (type: Music) -Function 581: PauseMusicStream() (1 input parameters) +Function 585: PauseMusicStream() (1 input parameters) Name: PauseMusicStream Return type: void Description: Pause music playing Param[1]: music (type: Music) -Function 582: ResumeMusicStream() (1 input parameters) +Function 586: ResumeMusicStream() (1 input parameters) Name: ResumeMusicStream Return type: void Description: Resume playing paused music Param[1]: music (type: Music) -Function 583: SeekMusicStream() (2 input parameters) +Function 587: SeekMusicStream() (2 input parameters) Name: SeekMusicStream Return type: void Description: Seek music to a position (in seconds) Param[1]: music (type: Music) Param[2]: position (type: float) -Function 584: SetMusicVolume() (2 input parameters) +Function 588: SetMusicVolume() (2 input parameters) Name: SetMusicVolume Return type: void Description: Set volume for music (1.0 is max level) Param[1]: music (type: Music) Param[2]: volume (type: float) -Function 585: SetMusicPitch() (2 input parameters) +Function 589: SetMusicPitch() (2 input parameters) Name: SetMusicPitch Return type: void Description: Set pitch for music (1.0 is base level) Param[1]: music (type: Music) Param[2]: pitch (type: float) -Function 586: SetMusicPan() (2 input parameters) +Function 590: SetMusicPan() (2 input parameters) Name: SetMusicPan Return type: void Description: Set pan for music (-1.0 left, 0.0 center, 1.0 right) Param[1]: music (type: Music) Param[2]: pan (type: float) -Function 587: GetMusicTimeLength() (1 input parameters) +Function 591: GetMusicTimeLength() (1 input parameters) Name: GetMusicTimeLength Return type: float Description: Get music time length (in seconds) Param[1]: music (type: Music) -Function 588: GetMusicTimePlayed() (1 input parameters) +Function 592: GetMusicTimePlayed() (1 input parameters) Name: GetMusicTimePlayed Return type: float Description: Get current music time played (in seconds) Param[1]: music (type: Music) -Function 589: LoadAudioStream() (3 input parameters) +Function 593: LoadAudioStream() (3 input parameters) Name: LoadAudioStream Return type: AudioStream Description: Load audio stream (to stream raw audio pcm data) Param[1]: sampleRate (type: unsigned int) Param[2]: sampleSize (type: unsigned int) Param[3]: channels (type: unsigned int) -Function 590: IsAudioStreamValid() (1 input parameters) +Function 594: IsAudioStreamValid() (1 input parameters) Name: IsAudioStreamValid Return type: bool Description: Check if an audio stream is valid (buffers initialized) Param[1]: stream (type: AudioStream) -Function 591: UnloadAudioStream() (1 input parameters) +Function 595: UnloadAudioStream() (1 input parameters) Name: UnloadAudioStream Return type: void Description: Unload audio stream and free memory Param[1]: stream (type: AudioStream) -Function 592: UpdateAudioStream() (3 input parameters) +Function 596: UpdateAudioStream() (3 input parameters) Name: UpdateAudioStream Return type: void Description: Update audio stream buffers with data Param[1]: stream (type: AudioStream) Param[2]: data (type: const void *) Param[3]: frameCount (type: int) -Function 593: IsAudioStreamProcessed() (1 input parameters) +Function 597: IsAudioStreamProcessed() (1 input parameters) Name: IsAudioStreamProcessed Return type: bool Description: Check if any audio stream buffers requires refill Param[1]: stream (type: AudioStream) -Function 594: PlayAudioStream() (1 input parameters) +Function 598: PlayAudioStream() (1 input parameters) Name: PlayAudioStream Return type: void Description: Play audio stream Param[1]: stream (type: AudioStream) -Function 595: PauseAudioStream() (1 input parameters) +Function 599: PauseAudioStream() (1 input parameters) Name: PauseAudioStream Return type: void Description: Pause audio stream Param[1]: stream (type: AudioStream) -Function 596: ResumeAudioStream() (1 input parameters) +Function 600: ResumeAudioStream() (1 input parameters) Name: ResumeAudioStream Return type: void Description: Resume audio stream Param[1]: stream (type: AudioStream) -Function 597: IsAudioStreamPlaying() (1 input parameters) +Function 601: IsAudioStreamPlaying() (1 input parameters) Name: IsAudioStreamPlaying Return type: bool Description: Check if audio stream is playing Param[1]: stream (type: AudioStream) -Function 598: StopAudioStream() (1 input parameters) +Function 602: StopAudioStream() (1 input parameters) Name: StopAudioStream Return type: void Description: Stop audio stream Param[1]: stream (type: AudioStream) -Function 599: SetAudioStreamVolume() (2 input parameters) +Function 603: SetAudioStreamVolume() (2 input parameters) Name: SetAudioStreamVolume Return type: void Description: Set volume for audio stream (1.0 is max level) Param[1]: stream (type: AudioStream) Param[2]: volume (type: float) -Function 600: SetAudioStreamPitch() (2 input parameters) +Function 604: SetAudioStreamPitch() (2 input parameters) Name: SetAudioStreamPitch Return type: void Description: Set pitch for audio stream (1.0 is base level) Param[1]: stream (type: AudioStream) Param[2]: pitch (type: float) -Function 601: SetAudioStreamPan() (2 input parameters) +Function 605: SetAudioStreamPan() (2 input parameters) Name: SetAudioStreamPan Return type: void Description: Set pan for audio stream (-1.0 left, 0.0 center, 1.0 right) Param[1]: stream (type: AudioStream) Param[2]: pan (type: float) -Function 602: SetAudioStreamBufferSizeDefault() (1 input parameters) +Function 606: SetAudioStreamBufferSizeDefault() (1 input parameters) Name: SetAudioStreamBufferSizeDefault Return type: void Description: Default size for new audio streams Param[1]: size (type: int) -Function 603: SetAudioStreamCallback() (2 input parameters) +Function 607: SetAudioStreamCallback() (2 input parameters) Name: SetAudioStreamCallback Return type: void Description: Audio thread callback to request new data Param[1]: stream (type: AudioStream) Param[2]: callback (type: AudioCallback) -Function 604: AttachAudioStreamProcessor() (2 input parameters) +Function 608: AttachAudioStreamProcessor() (2 input parameters) Name: AttachAudioStreamProcessor Return type: void Description: Attach audio stream processor to stream, receives frames x 2 samples as 'float' (stereo) Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 605: DetachAudioStreamProcessor() (2 input parameters) +Function 609: DetachAudioStreamProcessor() (2 input parameters) Name: DetachAudioStreamProcessor Return type: void Description: Detach audio stream processor from stream Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 606: AttachAudioMixedProcessor() (1 input parameters) +Function 610: AttachAudioMixedProcessor() (1 input parameters) Name: AttachAudioMixedProcessor Return type: void Description: Attach audio stream processor to the entire audio pipeline, receives frames x 2 samples as 'float' (stereo) Param[1]: processor (type: AudioCallback) -Function 607: DetachAudioMixedProcessor() (1 input parameters) +Function 611: DetachAudioMixedProcessor() (1 input parameters) Name: DetachAudioMixedProcessor Return type: void Description: Detach audio stream processor from the entire audio pipeline diff --git a/tools/rlparser/output/raylib_api.xml b/tools/rlparser/output/raylib_api.xml index ec7711ee7..6dd00a610 100644 --- a/tools/rlparser/output/raylib_api.xml +++ b/tools/rlparser/output/raylib_api.xml @@ -681,7 +681,7 @@ - + @@ -2132,6 +2132,13 @@ + + + + + + + @@ -2146,6 +2153,14 @@ + + + + + + + + @@ -2186,6 +2201,14 @@ + + + + + + + + @@ -2219,6 +2242,17 @@ + + + + + + + + + + + From 44b16a548f3aea27eb14c10261e81930b165d84e Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 1 Jul 2026 12:18:58 +0200 Subject: [PATCH 23/94] Update rtextures.c --- src/rtextures.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rtextures.c b/src/rtextures.c index ce79c5627..6092cb57c 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -4219,7 +4219,7 @@ void ImageDrawTextEx(Image *dst, Font font, const char *text, Vector2 position, // Draw text using Font and pro parameters (rotation) void ImageDrawTextPro(Image *dst, Font font, const char *text, Vector2 position, Vector2 origin, float rotation, float fontSize, float spacing, Color tint) { - // TODO: NEW: Implement ImageDrawImageEx() + // TODO: NEW: Implement ImageDrawTextPro() } //------------------------------------------------------------------------------------ From 77ecd5befc12240a58b4b4833b9c2c258c6c4ed3 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 2 Jul 2026 10:46:38 +0200 Subject: [PATCH 24/94] REVIEWED: `TextToSnake()`, not considering spaces properly --- src/rtext.c | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/rtext.c b/src/rtext.c index dda08b11e..9d5943ce8 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -2200,18 +2200,43 @@ char *TextToSnake(const char *text) if (text != NULL) { // Check for next separator to upper case another character - for (int i = 0, j = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[j] != '\0'); i++, j++) + for (int i = 0, j = 0; (i < MAX_TEXT_BUFFER_LENGTH - 1) && (text[j] != '\0'); j++) { - if ((text[j] >= 'A') && (text[j] <= 'Z')) + if (text[j] == ' ') { - if (i >= 1) + if ((i > 0) && (buffer[i - 1] != '_')) { buffer[i] = '_'; i++; } - buffer[i] = text[j] + 32; } - else buffer[i] = text[j]; + else if ((text[j] >= 'A') && (text[j] <= 'Z')) + { + if ((i > 0) && (buffer[i - 1] != '_')) + { + char prev = text[j - 1]; + char next = text[j + 1]; + + // Considering multiple cap leters to be on single word (HTTPRequest --> http_request) + if (((prev >= 'a') && (prev <= 'z')) || + (((prev >= 'A') && (prev <= 'Z')) && ((next >= 'a') && (next <= 'z')))) + { + if (i < MAX_TEXT_BUFFER_LENGTH - 2) + { + buffer[i] = '_'; + i++; + } + } + } + + buffer[i] = text[j] + 32; + i++; + } + else + { + buffer[i] = text[j]; + i++; + } } } From 0c0375f8ae6ff4c9ac14b36611153d02b7dd6e96 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 2 Jul 2026 10:49:31 +0200 Subject: [PATCH 25/94] ADDED: `IsPathDirectory()`, for convenience and more readability at user code --- src/raylib.h | 3 ++- src/rcore.c | 20 +++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index 445b0a875..35f3c40a9 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1160,7 +1160,8 @@ RLAPI const char *GetWorkingDirectory(void); // Get curre RLAPI const char *GetApplicationDirectory(void); // Get the directory of the running application (uses static string) RLAPI int MakeDirectory(const char *dirPath); // Create directories (including full path requested), returns 0 on success RLAPI int ChangeDirectory(const char *dirPath); // Change working directory, returns 0 on success -RLAPI bool IsPathFile(const char *path); // Check if given path is a file or a directory +RLAPI bool IsPathFile(const char *path); // Check if given path points to a file +RLAPI bool IsPathDirectory(const char *path); // Check if given path points to a directory RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths, files and directories, no subdirs scan RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and subdir scan; some filters available: '*.*','FILES*','DIRS*' diff --git a/src/rcore.c b/src/rcore.c index 070b8c0c4..d1163a515 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -2825,10 +2825,24 @@ int ChangeDirectory(const char *dirPath) // Check if given path point to a file bool IsPathFile(const char *path) { - struct stat result = { 0 }; - stat(path, &result); + bool result = false; - return S_ISREG(result.st_mode); + struct stat info = { 0 }; + stat(path, &info); + + if (S_ISREG(info.st_mode)) result = true; + + return result; +} + +// Check if given path point to a directory +bool IsPathDirectory(const char *path) +{ + bool result = false; + + if (!IsPathFile(path)) result = true; + + return result; } // Check if fileName is valid for the platform/OS From 9f60957b84525aefee045a25e6b8628f75e05f6a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 2 Jul 2026 08:49:50 +0000 Subject: [PATCH 26/94] rlparser: update raylib_api.* by CI --- tools/rlparser/output/raylib_api.json | 13 +- tools/rlparser/output/raylib_api.lua | 10 +- tools/rlparser/output/raylib_api.sexpr | 8 +- tools/rlparser/output/raylib_api.txt | 943 +++++++++++++------------ tools/rlparser/output/raylib_api.xml | 7 +- 5 files changed, 507 insertions(+), 474 deletions(-) diff --git a/tools/rlparser/output/raylib_api.json b/tools/rlparser/output/raylib_api.json index ffac7e6da..de1ebc884 100644 --- a/tools/rlparser/output/raylib_api.json +++ b/tools/rlparser/output/raylib_api.json @@ -4657,7 +4657,18 @@ }, { "name": "IsPathFile", - "description": "Check if given path is a file or a directory", + "description": "Check if given path points to a file", + "returnType": "bool", + "params": [ + { + "type": "const char *", + "name": "path" + } + ] + }, + { + "name": "IsPathDirectory", + "description": "Check if given path points to a directory", "returnType": "bool", "params": [ { diff --git a/tools/rlparser/output/raylib_api.lua b/tools/rlparser/output/raylib_api.lua index 945e864ac..98308682d 100644 --- a/tools/rlparser/output/raylib_api.lua +++ b/tools/rlparser/output/raylib_api.lua @@ -4177,7 +4177,15 @@ return { }, { name = "IsPathFile", - description = "Check if given path is a file or a directory", + description = "Check if given path points to a file", + returnType = "bool", + params = { + {type = "const char *", name = "path"} + } + }, + { + name = "IsPathDirectory", + description = "Check if given path points to a directory", returnType = "bool", params = { {type = "const char *", name = "path"} diff --git a/tools/rlparser/output/raylib_api.sexpr b/tools/rlparser/output/raylib_api.sexpr index bb35bea10..e4dee877c 100644 --- a/tools/rlparser/output/raylib_api.sexpr +++ b/tools/rlparser/output/raylib_api.sexpr @@ -3033,7 +3033,13 @@ ((type "const char *") (name "dirPath")))) ((name "IsPathFile") - (description "Check if given path is a file or a directory") + (description "Check if given path points to a file") + (return-type "bool") + (params + ((type "const char *") (name "path")))) + + ((name "IsPathDirectory") + (description "Check if given path points to a directory") (return-type "bool") (params ((type "const char *") (name "path")))) diff --git a/tools/rlparser/output/raylib_api.txt b/tools/rlparser/output/raylib_api.txt index 47b5fd6f3..77a1dba1f 100644 --- a/tools/rlparser/output/raylib_api.txt +++ b/tools/rlparser/output/raylib_api.txt @@ -995,7 +995,7 @@ Callback 006: AudioCallback() (2 input parameters) Param[1]: bufferData (type: void *) Param[2]: frames (type: unsigned int) -Functions found: 611 +Functions found: 612 Function 001: InitWindow() (3 input parameters) Name: InitWindow @@ -1769,250 +1769,255 @@ Function 143: ChangeDirectory() (1 input parameters) Function 144: IsPathFile() (1 input parameters) Name: IsPathFile Return type: bool - Description: Check if given path is a file or a directory + Description: Check if given path points to a file Param[1]: path (type: const char *) -Function 145: IsFileNameValid() (1 input parameters) +Function 145: IsPathDirectory() (1 input parameters) + Name: IsPathDirectory + Return type: bool + Description: Check if given path points to a directory + Param[1]: path (type: const char *) +Function 146: IsFileNameValid() (1 input parameters) Name: IsFileNameValid Return type: bool Description: Check if fileName is valid for the platform/OS Param[1]: fileName (type: const char *) -Function 146: LoadDirectoryFiles() (1 input parameters) +Function 147: LoadDirectoryFiles() (1 input parameters) Name: LoadDirectoryFiles Return type: FilePathList Description: Load directory filepaths, files and directories, no subdirs scan Param[1]: dirPath (type: const char *) -Function 147: LoadDirectoryFilesEx() (3 input parameters) +Function 148: LoadDirectoryFilesEx() (3 input parameters) Name: LoadDirectoryFilesEx Return type: FilePathList Description: Load directory filepaths with extension filtering and subdir scan; some filters available: '*.*','FILES*','DIRS*' Param[1]: basePath (type: const char *) Param[2]: filter (type: const char *) Param[3]: scanSubdirs (type: bool) -Function 148: UnloadDirectoryFiles() (1 input parameters) +Function 149: UnloadDirectoryFiles() (1 input parameters) Name: UnloadDirectoryFiles Return type: void Description: Unload filepaths Param[1]: files (type: FilePathList) -Function 149: IsFileDropped() (0 input parameters) +Function 150: IsFileDropped() (0 input parameters) Name: IsFileDropped Return type: bool Description: Check if file has been dropped into window No input parameters -Function 150: LoadDroppedFiles() (0 input parameters) +Function 151: LoadDroppedFiles() (0 input parameters) Name: LoadDroppedFiles Return type: FilePathList Description: Load dropped filepaths No input parameters -Function 151: UnloadDroppedFiles() (1 input parameters) +Function 152: UnloadDroppedFiles() (1 input parameters) Name: UnloadDroppedFiles Return type: void Description: Unload dropped filepaths Param[1]: files (type: FilePathList) -Function 152: GetDirectoryFileCount() (1 input parameters) +Function 153: GetDirectoryFileCount() (1 input parameters) Name: GetDirectoryFileCount Return type: unsigned int Description: Get the file count in a directory Param[1]: dirPath (type: const char *) -Function 153: GetDirectoryFileCountEx() (3 input parameters) +Function 154: GetDirectoryFileCountEx() (3 input parameters) Name: GetDirectoryFileCountEx Return type: unsigned int Description: Get the file count in a directory with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result Param[1]: basePath (type: const char *) Param[2]: filter (type: const char *) Param[3]: scanSubdirs (type: bool) -Function 154: CompressData() (3 input parameters) +Function 155: CompressData() (3 input parameters) Name: CompressData Return type: unsigned char * Description: Compress data (DEFLATE algorithm), memory must be MemFree() Param[1]: data (type: const unsigned char *) Param[2]: dataSize (type: int) Param[3]: compDataSize (type: int *) -Function 155: DecompressData() (3 input parameters) +Function 156: DecompressData() (3 input parameters) Name: DecompressData Return type: unsigned char * Description: Decompress data (DEFLATE algorithm), memory must be MemFree() Param[1]: compData (type: const unsigned char *) Param[2]: compDataSize (type: int) Param[3]: dataSize (type: int *) -Function 156: EncodeDataBase64() (3 input parameters) +Function 157: EncodeDataBase64() (3 input parameters) Name: EncodeDataBase64 Return type: char * Description: Encode data to Base64 string (includes NULL terminator), memory must be MemFree() Param[1]: data (type: const unsigned char *) Param[2]: dataSize (type: int) Param[3]: outputSize (type: int *) -Function 157: DecodeDataBase64() (2 input parameters) +Function 158: DecodeDataBase64() (2 input parameters) Name: DecodeDataBase64 Return type: unsigned char * Description: Decode Base64 string (expected NULL terminated), memory must be MemFree() Param[1]: text (type: const char *) Param[2]: outputSize (type: int *) -Function 158: ComputeCRC32() (2 input parameters) +Function 159: ComputeCRC32() (2 input parameters) Name: ComputeCRC32 Return type: unsigned int Description: Compute CRC32 hash code Param[1]: data (type: const unsigned char *) Param[2]: dataSize (type: int) -Function 159: ComputeMD5() (2 input parameters) +Function 160: ComputeMD5() (2 input parameters) Name: ComputeMD5 Return type: unsigned int * Description: Compute MD5 hash code, returns static int[4] (16 bytes) Param[1]: data (type: const unsigned char *) Param[2]: dataSize (type: int) -Function 160: ComputeSHA1() (2 input parameters) +Function 161: ComputeSHA1() (2 input parameters) Name: ComputeSHA1 Return type: unsigned int * Description: Compute SHA1 hash code, returns static int[5] (20 bytes) Param[1]: data (type: const unsigned char *) Param[2]: dataSize (type: int) -Function 161: ComputeSHA256() (2 input parameters) +Function 162: ComputeSHA256() (2 input parameters) Name: ComputeSHA256 Return type: unsigned int * Description: Compute SHA256 hash code, returns static int[8] (32 bytes) Param[1]: data (type: const unsigned char *) Param[2]: dataSize (type: int) -Function 162: LoadAutomationEventList() (1 input parameters) +Function 163: LoadAutomationEventList() (1 input parameters) Name: LoadAutomationEventList Return type: AutomationEventList Description: Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS Param[1]: fileName (type: const char *) -Function 163: UnloadAutomationEventList() (1 input parameters) +Function 164: UnloadAutomationEventList() (1 input parameters) Name: UnloadAutomationEventList Return type: void Description: Unload automation events list from file Param[1]: list (type: AutomationEventList) -Function 164: ExportAutomationEventList() (2 input parameters) +Function 165: ExportAutomationEventList() (2 input parameters) Name: ExportAutomationEventList Return type: bool Description: Export automation events list as text file Param[1]: list (type: AutomationEventList) Param[2]: fileName (type: const char *) -Function 165: SetAutomationEventList() (1 input parameters) +Function 166: SetAutomationEventList() (1 input parameters) Name: SetAutomationEventList Return type: void Description: Set automation event list to record to Param[1]: list (type: AutomationEventList *) -Function 166: SetAutomationEventBaseFrame() (1 input parameters) +Function 167: SetAutomationEventBaseFrame() (1 input parameters) Name: SetAutomationEventBaseFrame Return type: void Description: Set automation event internal base frame to start recording Param[1]: frame (type: int) -Function 167: StartAutomationEventRecording() (0 input parameters) +Function 168: StartAutomationEventRecording() (0 input parameters) Name: StartAutomationEventRecording Return type: void Description: Start recording automation events (AutomationEventList must be set) No input parameters -Function 168: StopAutomationEventRecording() (0 input parameters) +Function 169: StopAutomationEventRecording() (0 input parameters) Name: StopAutomationEventRecording Return type: void Description: Stop recording automation events No input parameters -Function 169: PlayAutomationEvent() (1 input parameters) +Function 170: PlayAutomationEvent() (1 input parameters) Name: PlayAutomationEvent Return type: void Description: Play a recorded automation event Param[1]: event (type: AutomationEvent) -Function 170: IsKeyPressed() (1 input parameters) +Function 171: IsKeyPressed() (1 input parameters) Name: IsKeyPressed Return type: bool Description: Check if key has been pressed once Param[1]: key (type: int) -Function 171: IsKeyPressedRepeat() (1 input parameters) +Function 172: IsKeyPressedRepeat() (1 input parameters) Name: IsKeyPressedRepeat Return type: bool Description: Check if key has been pressed again Param[1]: key (type: int) -Function 172: IsKeyDown() (1 input parameters) +Function 173: IsKeyDown() (1 input parameters) Name: IsKeyDown Return type: bool Description: Check if key is being pressed Param[1]: key (type: int) -Function 173: IsKeyReleased() (1 input parameters) +Function 174: IsKeyReleased() (1 input parameters) Name: IsKeyReleased Return type: bool Description: Check if key has been released once Param[1]: key (type: int) -Function 174: IsKeyUp() (1 input parameters) +Function 175: IsKeyUp() (1 input parameters) Name: IsKeyUp Return type: bool Description: Check if key is NOT being pressed Param[1]: key (type: int) -Function 175: GetKeyPressed() (0 input parameters) +Function 176: GetKeyPressed() (0 input parameters) Name: GetKeyPressed Return type: int Description: Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty No input parameters -Function 176: GetCharPressed() (0 input parameters) +Function 177: GetCharPressed() (0 input parameters) Name: GetCharPressed Return type: int Description: Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty No input parameters -Function 177: GetKeyName() (1 input parameters) +Function 178: GetKeyName() (1 input parameters) Name: GetKeyName Return type: const char * Description: Get name of a QWERTY key on the current keyboard layout (eg returns string 'q' for KEY_A on an AZERTY keyboard) Param[1]: key (type: int) -Function 178: SetExitKey() (1 input parameters) +Function 179: SetExitKey() (1 input parameters) Name: SetExitKey Return type: void Description: Set a custom key to exit program (default is ESC) Param[1]: key (type: int) -Function 179: IsGamepadAvailable() (1 input parameters) +Function 180: IsGamepadAvailable() (1 input parameters) Name: IsGamepadAvailable Return type: bool Description: Check if gamepad is available Param[1]: gamepad (type: int) -Function 180: GetGamepadName() (1 input parameters) +Function 181: GetGamepadName() (1 input parameters) Name: GetGamepadName Return type: const char * Description: Get gamepad internal name id Param[1]: gamepad (type: int) -Function 181: IsGamepadButtonPressed() (2 input parameters) +Function 182: IsGamepadButtonPressed() (2 input parameters) Name: IsGamepadButtonPressed Return type: bool Description: Check if gamepad button has been pressed once Param[1]: gamepad (type: int) Param[2]: button (type: int) -Function 182: IsGamepadButtonDown() (2 input parameters) +Function 183: IsGamepadButtonDown() (2 input parameters) Name: IsGamepadButtonDown Return type: bool Description: Check if gamepad button is being pressed Param[1]: gamepad (type: int) Param[2]: button (type: int) -Function 183: IsGamepadButtonReleased() (2 input parameters) +Function 184: IsGamepadButtonReleased() (2 input parameters) Name: IsGamepadButtonReleased Return type: bool Description: Check if gamepad button has been released once Param[1]: gamepad (type: int) Param[2]: button (type: int) -Function 184: IsGamepadButtonUp() (2 input parameters) +Function 185: IsGamepadButtonUp() (2 input parameters) Name: IsGamepadButtonUp Return type: bool Description: Check if gamepad button is NOT being pressed Param[1]: gamepad (type: int) Param[2]: button (type: int) -Function 185: GetGamepadButtonPressed() (0 input parameters) +Function 186: GetGamepadButtonPressed() (0 input parameters) Name: GetGamepadButtonPressed Return type: int Description: Get the last gamepad button pressed No input parameters -Function 186: GetGamepadAxisCount() (1 input parameters) +Function 187: GetGamepadAxisCount() (1 input parameters) Name: GetGamepadAxisCount Return type: int Description: Get axis count for a gamepad Param[1]: gamepad (type: int) -Function 187: GetGamepadAxisMovement() (2 input parameters) +Function 188: GetGamepadAxisMovement() (2 input parameters) Name: GetGamepadAxisMovement Return type: float Description: Get movement value for a gamepad axis Param[1]: gamepad (type: int) Param[2]: axis (type: int) -Function 188: SetGamepadMappings() (1 input parameters) +Function 189: SetGamepadMappings() (1 input parameters) Name: SetGamepadMappings Return type: int Description: Set internal gamepad mappings (SDL_GameControllerDB) Param[1]: mappings (type: const char *) -Function 189: SetGamepadVibration() (4 input parameters) +Function 190: SetGamepadVibration() (4 input parameters) Name: SetGamepadVibration Return type: void Description: Set gamepad vibration for both motors (duration in seconds) @@ -2020,151 +2025,151 @@ Function 189: SetGamepadVibration() (4 input parameters) Param[2]: leftMotor (type: float) Param[3]: rightMotor (type: float) Param[4]: duration (type: float) -Function 190: IsMouseButtonPressed() (1 input parameters) +Function 191: IsMouseButtonPressed() (1 input parameters) Name: IsMouseButtonPressed Return type: bool Description: Check if mouse button has been pressed once Param[1]: button (type: int) -Function 191: IsMouseButtonDown() (1 input parameters) +Function 192: IsMouseButtonDown() (1 input parameters) Name: IsMouseButtonDown Return type: bool Description: Check if mouse button is being pressed Param[1]: button (type: int) -Function 192: IsMouseButtonReleased() (1 input parameters) +Function 193: IsMouseButtonReleased() (1 input parameters) Name: IsMouseButtonReleased Return type: bool Description: Check if mouse button has been released once Param[1]: button (type: int) -Function 193: IsMouseButtonUp() (1 input parameters) +Function 194: IsMouseButtonUp() (1 input parameters) Name: IsMouseButtonUp Return type: bool Description: Check if mouse button is NOT being pressed Param[1]: button (type: int) -Function 194: GetMouseX() (0 input parameters) +Function 195: GetMouseX() (0 input parameters) Name: GetMouseX Return type: int Description: Get mouse position X No input parameters -Function 195: GetMouseY() (0 input parameters) +Function 196: GetMouseY() (0 input parameters) Name: GetMouseY Return type: int Description: Get mouse position Y No input parameters -Function 196: GetMousePosition() (0 input parameters) +Function 197: GetMousePosition() (0 input parameters) Name: GetMousePosition Return type: Vector2 Description: Get mouse position XY No input parameters -Function 197: GetMouseDelta() (0 input parameters) +Function 198: GetMouseDelta() (0 input parameters) Name: GetMouseDelta Return type: Vector2 Description: Get mouse delta between frames No input parameters -Function 198: SetMousePosition() (2 input parameters) +Function 199: SetMousePosition() (2 input parameters) Name: SetMousePosition Return type: void Description: Set mouse position XY Param[1]: x (type: int) Param[2]: y (type: int) -Function 199: SetMouseOffset() (2 input parameters) +Function 200: SetMouseOffset() (2 input parameters) Name: SetMouseOffset Return type: void Description: Set mouse offset Param[1]: offsetX (type: int) Param[2]: offsetY (type: int) -Function 200: SetMouseScale() (2 input parameters) +Function 201: SetMouseScale() (2 input parameters) Name: SetMouseScale Return type: void Description: Set mouse scaling Param[1]: scaleX (type: float) Param[2]: scaleY (type: float) -Function 201: GetMouseWheelMove() (0 input parameters) +Function 202: GetMouseWheelMove() (0 input parameters) Name: GetMouseWheelMove Return type: float Description: Get mouse wheel movement for X or Y, whichever is larger No input parameters -Function 202: GetMouseWheelMoveV() (0 input parameters) +Function 203: GetMouseWheelMoveV() (0 input parameters) Name: GetMouseWheelMoveV Return type: Vector2 Description: Get mouse wheel movement for both X and Y No input parameters -Function 203: SetMouseCursor() (1 input parameters) +Function 204: SetMouseCursor() (1 input parameters) Name: SetMouseCursor Return type: void Description: Set mouse cursor Param[1]: cursor (type: int) -Function 204: GetTouchX() (0 input parameters) +Function 205: GetTouchX() (0 input parameters) Name: GetTouchX Return type: int Description: Get touch position X for touch point 0 (relative to screen size) No input parameters -Function 205: GetTouchY() (0 input parameters) +Function 206: GetTouchY() (0 input parameters) Name: GetTouchY Return type: int Description: Get touch position Y for touch point 0 (relative to screen size) No input parameters -Function 206: GetTouchPosition() (1 input parameters) +Function 207: GetTouchPosition() (1 input parameters) Name: GetTouchPosition Return type: Vector2 Description: Get touch position XY for a touch point index (relative to screen size) Param[1]: index (type: int) -Function 207: GetTouchPointId() (1 input parameters) +Function 208: GetTouchPointId() (1 input parameters) Name: GetTouchPointId Return type: int Description: Get touch point identifier for given index Param[1]: index (type: int) -Function 208: GetTouchPointCount() (0 input parameters) +Function 209: GetTouchPointCount() (0 input parameters) Name: GetTouchPointCount Return type: int Description: Get number of touch points No input parameters -Function 209: SetGesturesEnabled() (1 input parameters) +Function 210: SetGesturesEnabled() (1 input parameters) Name: SetGesturesEnabled Return type: void Description: Enable a set of gestures using flags Param[1]: flags (type: unsigned int) -Function 210: IsGestureDetected() (1 input parameters) +Function 211: IsGestureDetected() (1 input parameters) Name: IsGestureDetected Return type: bool Description: Check if gesture has been detected Param[1]: gesture (type: unsigned int) -Function 211: GetGestureDetected() (0 input parameters) +Function 212: GetGestureDetected() (0 input parameters) Name: GetGestureDetected Return type: int Description: Get latest detected gesture No input parameters -Function 212: GetGestureHoldDuration() (0 input parameters) +Function 213: GetGestureHoldDuration() (0 input parameters) Name: GetGestureHoldDuration Return type: float Description: Get gesture hold time in seconds No input parameters -Function 213: GetGestureDragVector() (0 input parameters) +Function 214: GetGestureDragVector() (0 input parameters) Name: GetGestureDragVector Return type: Vector2 Description: Get gesture drag vector No input parameters -Function 214: GetGestureDragAngle() (0 input parameters) +Function 215: GetGestureDragAngle() (0 input parameters) Name: GetGestureDragAngle Return type: float Description: Get gesture drag angle No input parameters -Function 215: GetGesturePinchVector() (0 input parameters) +Function 216: GetGesturePinchVector() (0 input parameters) Name: GetGesturePinchVector Return type: Vector2 Description: Get gesture pinch delta No input parameters -Function 216: GetGesturePinchAngle() (0 input parameters) +Function 217: GetGesturePinchAngle() (0 input parameters) Name: GetGesturePinchAngle Return type: float Description: Get gesture pinch angle No input parameters -Function 217: UpdateCamera() (2 input parameters) +Function 218: UpdateCamera() (2 input parameters) Name: UpdateCamera Return type: void Description: Update camera position for selected mode Param[1]: camera (type: Camera *) Param[2]: mode (type: int) -Function 218: UpdateCameraPro() (4 input parameters) +Function 219: UpdateCameraPro() (4 input parameters) Name: UpdateCameraPro Return type: void Description: Update camera movement/rotation @@ -2172,36 +2177,36 @@ Function 218: UpdateCameraPro() (4 input parameters) Param[2]: movement (type: Vector3) Param[3]: rotation (type: Vector3) Param[4]: zoom (type: float) -Function 219: SetShapesTexture() (2 input parameters) +Function 220: SetShapesTexture() (2 input parameters) Name: SetShapesTexture Return type: void Description: Set texture and rectangle to be used on shapes drawing Param[1]: texture (type: Texture2D) Param[2]: rec (type: Rectangle) -Function 220: GetShapesTexture() (0 input parameters) +Function 221: GetShapesTexture() (0 input parameters) Name: GetShapesTexture Return type: Texture2D Description: Get texture that is used for shapes drawing No input parameters -Function 221: GetShapesTextureRectangle() (0 input parameters) +Function 222: GetShapesTextureRectangle() (0 input parameters) Name: GetShapesTextureRectangle Return type: Rectangle Description: Get texture source rectangle that is used for shapes drawing No input parameters -Function 222: DrawPixel() (3 input parameters) +Function 223: DrawPixel() (3 input parameters) Name: DrawPixel Return type: void Description: Draw a pixel using geometry [Can be slow, use with care] Param[1]: posX (type: int) Param[2]: posY (type: int) Param[3]: color (type: Color) -Function 223: DrawPixelV() (2 input parameters) +Function 224: DrawPixelV() (2 input parameters) Name: DrawPixelV Return type: void Description: Draw a pixel using geometry (Vector version) [Can be slow, use with care] Param[1]: position (type: Vector2) Param[2]: color (type: Color) -Function 224: DrawLine() (5 input parameters) +Function 225: DrawLine() (5 input parameters) Name: DrawLine Return type: void Description: Draw a line @@ -2210,14 +2215,14 @@ Function 224: DrawLine() (5 input parameters) Param[3]: endPosX (type: int) Param[4]: endPosY (type: int) Param[5]: color (type: Color) -Function 225: DrawLineV() (3 input parameters) +Function 226: DrawLineV() (3 input parameters) Name: DrawLineV Return type: void Description: Draw a line (using gl lines) Param[1]: startPos (type: Vector2) Param[2]: endPos (type: Vector2) Param[3]: color (type: Color) -Function 226: DrawLineEx() (4 input parameters) +Function 227: DrawLineEx() (4 input parameters) Name: DrawLineEx Return type: void Description: Draw a line (using triangles/quads) @@ -2225,14 +2230,14 @@ Function 226: DrawLineEx() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 227: DrawLineStrip() (3 input parameters) +Function 228: DrawLineStrip() (3 input parameters) Name: DrawLineStrip Return type: void Description: Draw lines sequence (using gl lines) Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 228: DrawLineBezier() (4 input parameters) +Function 229: DrawLineBezier() (4 input parameters) Name: DrawLineBezier Return type: void Description: Draw line segment cubic-bezier in-out interpolation @@ -2240,7 +2245,7 @@ Function 228: DrawLineBezier() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 229: DrawLineDashed() (5 input parameters) +Function 230: DrawLineDashed() (5 input parameters) Name: DrawLineDashed Return type: void Description: Draw a dashed line @@ -2249,7 +2254,7 @@ Function 229: DrawLineDashed() (5 input parameters) Param[3]: dashSize (type: int) Param[4]: spaceSize (type: int) Param[5]: color (type: Color) -Function 230: DrawTriangle() (4 input parameters) +Function 231: DrawTriangle() (4 input parameters) Name: DrawTriangle Return type: void Description: Draw a color-filled triangle, counter-clockwise vertex order @@ -2257,7 +2262,7 @@ Function 230: DrawTriangle() (4 input parameters) Param[2]: v2 (type: Vector2) Param[3]: v3 (type: Vector2) Param[4]: color (type: Color) -Function 231: DrawTriangleGradient() (6 input parameters) +Function 232: DrawTriangleGradient() (6 input parameters) Name: DrawTriangleGradient Return type: void Description: Draw triangle with interpolated colors, counter-clockwise vertex/color order @@ -2267,7 +2272,7 @@ Function 231: DrawTriangleGradient() (6 input parameters) Param[4]: c1 (type: Color) Param[5]: c2 (type: Color) Param[6]: c3 (type: Color) -Function 232: DrawTriangleLines() (4 input parameters) +Function 233: DrawTriangleLines() (4 input parameters) Name: DrawTriangleLines Return type: void Description: Draw triangle outline, counter-clockwise vertex order @@ -2275,21 +2280,21 @@ Function 232: DrawTriangleLines() (4 input parameters) Param[2]: v2 (type: Vector2) Param[3]: v3 (type: Vector2) Param[4]: color (type: Color) -Function 233: DrawTriangleFan() (3 input parameters) +Function 234: DrawTriangleFan() (3 input parameters) Name: DrawTriangleFan Return type: void Description: Draw a triangle fan defined by points (first vertex is the center) Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 234: DrawTriangleStrip() (3 input parameters) +Function 235: DrawTriangleStrip() (3 input parameters) Name: DrawTriangleStrip Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 235: DrawRectangle() (5 input parameters) +Function 236: DrawRectangle() (5 input parameters) Name: DrawRectangle Return type: void Description: Draw a color-filled rectangle @@ -2298,20 +2303,20 @@ Function 235: DrawRectangle() (5 input parameters) Param[3]: width (type: int) Param[4]: height (type: int) Param[5]: color (type: Color) -Function 236: DrawRectangleV() (3 input parameters) +Function 237: DrawRectangleV() (3 input parameters) Name: DrawRectangleV Return type: void Description: Draw a color-filled rectangle (Vector version) Param[1]: position (type: Vector2) Param[2]: size (type: Vector2) Param[3]: color (type: Color) -Function 237: DrawRectangleRec() (2 input parameters) +Function 238: DrawRectangleRec() (2 input parameters) Name: DrawRectangleRec Return type: void Description: Draw a color-filled rectangle Param[1]: rec (type: Rectangle) Param[2]: color (type: Color) -Function 238: DrawRectanglePro() (4 input parameters) +Function 239: DrawRectanglePro() (4 input parameters) Name: DrawRectanglePro Return type: void Description: Draw a color-filled rectangle with pro parameters @@ -2319,7 +2324,7 @@ Function 238: DrawRectanglePro() (4 input parameters) Param[2]: origin (type: Vector2) Param[3]: rotation (type: float) Param[4]: color (type: Color) -Function 239: DrawRectangleGradientV() (6 input parameters) +Function 240: DrawRectangleGradientV() (6 input parameters) Name: DrawRectangleGradientV Return type: void Description: Draw a vertical-gradient-filled rectangle @@ -2329,7 +2334,7 @@ Function 239: DrawRectangleGradientV() (6 input parameters) Param[4]: height (type: int) Param[5]: top (type: Color) Param[6]: bottom (type: Color) -Function 240: DrawRectangleGradientH() (6 input parameters) +Function 241: DrawRectangleGradientH() (6 input parameters) Name: DrawRectangleGradientH Return type: void Description: Draw a horizontal-gradient-filled rectangle @@ -2339,7 +2344,7 @@ Function 240: DrawRectangleGradientH() (6 input parameters) Param[4]: height (type: int) Param[5]: left (type: Color) Param[6]: right (type: Color) -Function 241: DrawRectangleGradientEx() (5 input parameters) +Function 242: DrawRectangleGradientEx() (5 input parameters) Name: DrawRectangleGradientEx Return type: void Description: Draw a gradient-filled rectangle with custom vertex colors, counter-clockwise color order @@ -2348,7 +2353,7 @@ Function 241: DrawRectangleGradientEx() (5 input parameters) Param[3]: col2 (type: Color) Param[4]: col3 (type: Color) Param[5]: col4 (type: Color) -Function 242: DrawRectangleLines() (5 input parameters) +Function 243: DrawRectangleLines() (5 input parameters) Name: DrawRectangleLines Return type: void Description: Draw rectangle outline @@ -2357,14 +2362,14 @@ Function 242: DrawRectangleLines() (5 input parameters) Param[3]: width (type: int) Param[4]: height (type: int) Param[5]: color (type: Color) -Function 243: DrawRectangleLinesEx() (3 input parameters) +Function 244: DrawRectangleLinesEx() (3 input parameters) Name: DrawRectangleLinesEx Return type: void Description: Draw rectangle outline with line thickness Param[1]: rec (type: Rectangle) Param[2]: thick (type: float) Param[3]: color (type: Color) -Function 244: DrawRectangleRounded() (4 input parameters) +Function 245: DrawRectangleRounded() (4 input parameters) Name: DrawRectangleRounded Return type: void Description: Draw rectangle with rounded edges @@ -2372,7 +2377,7 @@ Function 244: DrawRectangleRounded() (4 input parameters) Param[2]: roundness (type: float) Param[3]: segments (type: int) Param[4]: color (type: Color) -Function 245: DrawRectangleRoundedLines() (4 input parameters) +Function 246: DrawRectangleRoundedLines() (4 input parameters) Name: DrawRectangleRoundedLines Return type: void Description: Draw rectangle lines with rounded edges @@ -2380,7 +2385,7 @@ Function 245: DrawRectangleRoundedLines() (4 input parameters) Param[2]: roundness (type: float) Param[3]: segments (type: int) Param[4]: color (type: Color) -Function 246: DrawRectangleRoundedLinesEx() (5 input parameters) +Function 247: DrawRectangleRoundedLinesEx() (5 input parameters) Name: DrawRectangleRoundedLinesEx Return type: void Description: Draw rectangle lines with rounded edges outline and line thickness @@ -2389,7 +2394,7 @@ Function 246: DrawRectangleRoundedLinesEx() (5 input parameters) Param[3]: segments (type: int) Param[4]: thick (type: float) Param[5]: color (type: Color) -Function 247: DrawPoly() (5 input parameters) +Function 248: DrawPoly() (5 input parameters) Name: DrawPoly Return type: void Description: Draw a polygon of n sides @@ -2398,7 +2403,7 @@ Function 247: DrawPoly() (5 input parameters) Param[3]: radius (type: float) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 248: DrawPolyLines() (5 input parameters) +Function 249: DrawPolyLines() (5 input parameters) Name: DrawPolyLines Return type: void Description: Draw a polygon outline of n sides @@ -2407,7 +2412,7 @@ Function 248: DrawPolyLines() (5 input parameters) Param[3]: radius (type: float) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 249: DrawPolyLinesEx() (6 input parameters) +Function 250: DrawPolyLinesEx() (6 input parameters) Name: DrawPolyLinesEx Return type: void Description: Draw a polygon outline of n sides with line thickness @@ -2417,7 +2422,7 @@ Function 249: DrawPolyLinesEx() (6 input parameters) Param[4]: rotation (type: float) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 250: DrawCircle() (4 input parameters) +Function 251: DrawCircle() (4 input parameters) Name: DrawCircle Return type: void Description: Draw a color-filled circle @@ -2425,14 +2430,14 @@ Function 250: DrawCircle() (4 input parameters) Param[2]: centerY (type: int) Param[3]: radius (type: float) Param[4]: color (type: Color) -Function 251: DrawCircleV() (3 input parameters) +Function 252: DrawCircleV() (3 input parameters) Name: DrawCircleV Return type: void Description: Draw a color-filled circle (Vector version) Param[1]: center (type: Vector2) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 252: DrawCircleGradient() (4 input parameters) +Function 253: DrawCircleGradient() (4 input parameters) Name: DrawCircleGradient Return type: void Description: Draw a gradient-filled circle @@ -2440,7 +2445,7 @@ Function 252: DrawCircleGradient() (4 input parameters) Param[2]: radius (type: float) Param[3]: inner (type: Color) Param[4]: outer (type: Color) -Function 253: DrawCircleSector() (6 input parameters) +Function 254: DrawCircleSector() (6 input parameters) Name: DrawCircleSector Return type: void Description: Draw a piece of a circle @@ -2450,7 +2455,7 @@ Function 253: DrawCircleSector() (6 input parameters) Param[4]: endAngle (type: float) Param[5]: segments (type: int) Param[6]: color (type: Color) -Function 254: DrawCircleSectorLines() (6 input parameters) +Function 255: DrawCircleSectorLines() (6 input parameters) Name: DrawCircleSectorLines Return type: void Description: Draw circle sector outline @@ -2460,7 +2465,7 @@ Function 254: DrawCircleSectorLines() (6 input parameters) Param[4]: endAngle (type: float) Param[5]: segments (type: int) Param[6]: color (type: Color) -Function 255: DrawCircleLines() (4 input parameters) +Function 256: DrawCircleLines() (4 input parameters) Name: DrawCircleLines Return type: void Description: Draw circle outline @@ -2468,14 +2473,14 @@ Function 255: DrawCircleLines() (4 input parameters) Param[2]: centerY (type: int) Param[3]: radius (type: float) Param[4]: color (type: Color) -Function 256: DrawCircleLinesV() (3 input parameters) +Function 257: DrawCircleLinesV() (3 input parameters) Name: DrawCircleLinesV Return type: void Description: Draw circle outline (Vector version) Param[1]: center (type: Vector2) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 257: DrawCircleLinesEx() (4 input parameters) +Function 258: DrawCircleLinesEx() (4 input parameters) Name: DrawCircleLinesEx Return type: void Description: Draw circle outline with line thickness @@ -2483,7 +2488,7 @@ Function 257: DrawCircleLinesEx() (4 input parameters) Param[2]: radius (type: float) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 258: DrawEllipse() (5 input parameters) +Function 259: DrawEllipse() (5 input parameters) Name: DrawEllipse Return type: void Description: Draw ellipse @@ -2492,7 +2497,7 @@ Function 258: DrawEllipse() (5 input parameters) Param[3]: radiusH (type: float) Param[4]: radiusV (type: float) Param[5]: color (type: Color) -Function 259: DrawEllipseV() (4 input parameters) +Function 260: DrawEllipseV() (4 input parameters) Name: DrawEllipseV Return type: void Description: Draw ellipse (Vector version) @@ -2500,7 +2505,7 @@ Function 259: DrawEllipseV() (4 input parameters) Param[2]: radiusH (type: float) Param[3]: radiusV (type: float) Param[4]: color (type: Color) -Function 260: DrawEllipseLines() (5 input parameters) +Function 261: DrawEllipseLines() (5 input parameters) Name: DrawEllipseLines Return type: void Description: Draw ellipse outline @@ -2509,7 +2514,7 @@ Function 260: DrawEllipseLines() (5 input parameters) Param[3]: radiusH (type: float) Param[4]: radiusV (type: float) Param[5]: color (type: Color) -Function 261: DrawEllipseLinesV() (4 input parameters) +Function 262: DrawEllipseLinesV() (4 input parameters) Name: DrawEllipseLinesV Return type: void Description: Draw ellipse outline (Vector version) @@ -2517,7 +2522,7 @@ Function 261: DrawEllipseLinesV() (4 input parameters) Param[2]: radiusH (type: float) Param[3]: radiusV (type: float) Param[4]: color (type: Color) -Function 262: DrawRing() (7 input parameters) +Function 263: DrawRing() (7 input parameters) Name: DrawRing Return type: void Description: Draw ring @@ -2528,7 +2533,7 @@ Function 262: DrawRing() (7 input parameters) Param[5]: endAngle (type: float) Param[6]: segments (type: int) Param[7]: color (type: Color) -Function 263: DrawRingLines() (7 input parameters) +Function 264: DrawRingLines() (7 input parameters) Name: DrawRingLines Return type: void Description: Draw ring outline @@ -2539,7 +2544,7 @@ Function 263: DrawRingLines() (7 input parameters) Param[5]: endAngle (type: float) Param[6]: segments (type: int) Param[7]: color (type: Color) -Function 264: DrawSplineLinear() (4 input parameters) +Function 265: DrawSplineLinear() (4 input parameters) Name: DrawSplineLinear Return type: void Description: Draw spline: Linear, minimum 2 points @@ -2547,7 +2552,7 @@ Function 264: DrawSplineLinear() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 265: DrawSplineBasis() (4 input parameters) +Function 266: DrawSplineBasis() (4 input parameters) Name: DrawSplineBasis Return type: void Description: Draw spline: B-Spline, minimum 4 points @@ -2555,7 +2560,7 @@ Function 265: DrawSplineBasis() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 266: DrawSplineCatmullRom() (4 input parameters) +Function 267: DrawSplineCatmullRom() (4 input parameters) Name: DrawSplineCatmullRom Return type: void Description: Draw spline: Catmull-Rom, minimum 4 points @@ -2563,7 +2568,7 @@ Function 266: DrawSplineCatmullRom() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 267: DrawSplineBezierQuadratic() (4 input parameters) +Function 268: DrawSplineBezierQuadratic() (4 input parameters) Name: DrawSplineBezierQuadratic Return type: void Description: Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...] @@ -2571,7 +2576,7 @@ Function 267: DrawSplineBezierQuadratic() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 268: DrawSplineBezierCubic() (4 input parameters) +Function 269: DrawSplineBezierCubic() (4 input parameters) Name: DrawSplineBezierCubic Return type: void Description: Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...] @@ -2579,7 +2584,7 @@ Function 268: DrawSplineBezierCubic() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 269: DrawSplineSegmentLinear() (4 input parameters) +Function 270: DrawSplineSegmentLinear() (4 input parameters) Name: DrawSplineSegmentLinear Return type: void Description: Draw spline segment: Linear, 2 points @@ -2587,7 +2592,7 @@ Function 269: DrawSplineSegmentLinear() (4 input parameters) Param[2]: p2 (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 270: DrawSplineSegmentBasis() (6 input parameters) +Function 271: DrawSplineSegmentBasis() (6 input parameters) Name: DrawSplineSegmentBasis Return type: void Description: Draw spline segment: B-Spline, 4 points @@ -2597,7 +2602,7 @@ Function 270: DrawSplineSegmentBasis() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 271: DrawSplineSegmentCatmullRom() (6 input parameters) +Function 272: DrawSplineSegmentCatmullRom() (6 input parameters) Name: DrawSplineSegmentCatmullRom Return type: void Description: Draw spline segment: Catmull-Rom, 4 points @@ -2607,7 +2612,7 @@ Function 271: DrawSplineSegmentCatmullRom() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 272: DrawSplineSegmentBezierQuadratic() (5 input parameters) +Function 273: DrawSplineSegmentBezierQuadratic() (5 input parameters) Name: DrawSplineSegmentBezierQuadratic Return type: void Description: Draw spline segment: Quadratic Bezier, 2 points, 1 control point @@ -2616,7 +2621,7 @@ Function 272: DrawSplineSegmentBezierQuadratic() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: thick (type: float) Param[5]: color (type: Color) -Function 273: DrawSplineSegmentBezierCubic() (6 input parameters) +Function 274: DrawSplineSegmentBezierCubic() (6 input parameters) Name: DrawSplineSegmentBezierCubic Return type: void Description: Draw spline segment: Cubic Bezier, 2 points, 2 control points @@ -2626,14 +2631,14 @@ Function 273: DrawSplineSegmentBezierCubic() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 274: GetSplinePointLinear() (3 input parameters) +Function 275: GetSplinePointLinear() (3 input parameters) Name: GetSplinePointLinear Return type: Vector2 Description: Get (evaluate) spline point: Linear Param[1]: startPos (type: Vector2) Param[2]: endPos (type: Vector2) Param[3]: t (type: float) -Function 275: GetSplinePointBasis() (5 input parameters) +Function 276: GetSplinePointBasis() (5 input parameters) Name: GetSplinePointBasis Return type: Vector2 Description: Get (evaluate) spline point: B-Spline @@ -2642,7 +2647,7 @@ Function 275: GetSplinePointBasis() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 276: GetSplinePointCatmullRom() (5 input parameters) +Function 277: GetSplinePointCatmullRom() (5 input parameters) Name: GetSplinePointCatmullRom Return type: Vector2 Description: Get (evaluate) spline point: Catmull-Rom @@ -2651,7 +2656,7 @@ Function 276: GetSplinePointCatmullRom() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 277: GetSplinePointBezierQuadratic() (4 input parameters) +Function 278: GetSplinePointBezierQuadratic() (4 input parameters) Name: GetSplinePointBezierQuadratic Return type: Vector2 Description: Get (evaluate) spline point: Quadratic Bezier @@ -2659,7 +2664,7 @@ Function 277: GetSplinePointBezierQuadratic() (4 input parameters) Param[2]: c2 (type: Vector2) Param[3]: p3 (type: Vector2) Param[4]: t (type: float) -Function 278: GetSplinePointBezierCubic() (5 input parameters) +Function 279: GetSplinePointBezierCubic() (5 input parameters) Name: GetSplinePointBezierCubic Return type: Vector2 Description: Get (evaluate) spline point: Cubic Bezier @@ -2668,13 +2673,13 @@ Function 278: GetSplinePointBezierCubic() (5 input parameters) Param[3]: c3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 279: CheckCollisionRecs() (2 input parameters) +Function 280: CheckCollisionRecs() (2 input parameters) Name: CheckCollisionRecs Return type: bool Description: Check collision between two rectangles Param[1]: rec1 (type: Rectangle) Param[2]: rec2 (type: Rectangle) -Function 280: CheckCollisionCircles() (4 input parameters) +Function 281: CheckCollisionCircles() (4 input parameters) Name: CheckCollisionCircles Return type: bool Description: Check collision between two circles @@ -2682,14 +2687,14 @@ Function 280: CheckCollisionCircles() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector2) Param[4]: radius2 (type: float) -Function 281: CheckCollisionCircleRec() (3 input parameters) +Function 282: CheckCollisionCircleRec() (3 input parameters) Name: CheckCollisionCircleRec Return type: bool Description: Check collision between circle and rectangle Param[1]: center (type: Vector2) Param[2]: radius (type: float) Param[3]: rec (type: Rectangle) -Function 282: CheckCollisionCircleLine() (4 input parameters) +Function 283: CheckCollisionCircleLine() (4 input parameters) Name: CheckCollisionCircleLine Return type: bool Description: Check if circle collides with a line created between two points [p1] and [p2] @@ -2697,20 +2702,20 @@ Function 282: CheckCollisionCircleLine() (4 input parameters) Param[2]: radius (type: float) Param[3]: p1 (type: Vector2) Param[4]: p2 (type: Vector2) -Function 283: CheckCollisionPointRec() (2 input parameters) +Function 284: CheckCollisionPointRec() (2 input parameters) Name: CheckCollisionPointRec Return type: bool Description: Check if point is inside rectangle Param[1]: point (type: Vector2) Param[2]: rec (type: Rectangle) -Function 284: CheckCollisionPointCircle() (3 input parameters) +Function 285: CheckCollisionPointCircle() (3 input parameters) Name: CheckCollisionPointCircle Return type: bool Description: Check if point is inside circle Param[1]: point (type: Vector2) Param[2]: center (type: Vector2) Param[3]: radius (type: float) -Function 285: CheckCollisionPointTriangle() (4 input parameters) +Function 286: CheckCollisionPointTriangle() (4 input parameters) Name: CheckCollisionPointTriangle Return type: bool Description: Check if point is inside a triangle @@ -2718,7 +2723,7 @@ Function 285: CheckCollisionPointTriangle() (4 input parameters) Param[2]: p1 (type: Vector2) Param[3]: p2 (type: Vector2) Param[4]: p3 (type: Vector2) -Function 286: CheckCollisionPointLine() (4 input parameters) +Function 287: CheckCollisionPointLine() (4 input parameters) Name: CheckCollisionPointLine Return type: bool Description: Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold] @@ -2726,14 +2731,14 @@ Function 286: CheckCollisionPointLine() (4 input parameters) Param[2]: p1 (type: Vector2) Param[3]: p2 (type: Vector2) Param[4]: threshold (type: int) -Function 287: CheckCollisionPointPoly() (3 input parameters) +Function 288: CheckCollisionPointPoly() (3 input parameters) Name: CheckCollisionPointPoly Return type: bool Description: Check if point is within a polygon described by array of vertices Param[1]: point (type: Vector2) Param[2]: points (type: const Vector2 *) Param[3]: pointCount (type: int) -Function 288: CheckCollisionLines() (5 input parameters) +Function 289: CheckCollisionLines() (5 input parameters) Name: CheckCollisionLines Return type: bool Description: Check the collision between two lines defined by two points each, returns collision point by reference @@ -2742,18 +2747,18 @@ Function 288: CheckCollisionLines() (5 input parameters) Param[3]: startPos2 (type: Vector2) Param[4]: endPos2 (type: Vector2) Param[5]: collisionPoint (type: Vector2 *) -Function 289: GetCollisionRec() (2 input parameters) +Function 290: GetCollisionRec() (2 input parameters) Name: GetCollisionRec Return type: Rectangle Description: Get collision rectangle for two rectangles collision Param[1]: rec1 (type: Rectangle) Param[2]: rec2 (type: Rectangle) -Function 290: LoadImage() (1 input parameters) +Function 291: LoadImage() (1 input parameters) Name: LoadImage Return type: Image Description: Load image from file into CPU memory (RAM) Param[1]: fileName (type: const char *) -Function 291: LoadImageRaw() (5 input parameters) +Function 292: LoadImageRaw() (5 input parameters) Name: LoadImageRaw Return type: Image Description: Load image from RAW file data @@ -2762,13 +2767,13 @@ Function 291: LoadImageRaw() (5 input parameters) Param[3]: height (type: int) Param[4]: format (type: int) Param[5]: headerSize (type: int) -Function 292: LoadImageAnim() (2 input parameters) +Function 293: LoadImageAnim() (2 input parameters) Name: LoadImageAnim Return type: Image Description: Load image sequence from file (frames appended to image.data) Param[1]: fileName (type: const char *) Param[2]: frames (type: int *) -Function 293: LoadImageAnimFromMemory() (4 input parameters) +Function 294: LoadImageAnimFromMemory() (4 input parameters) Name: LoadImageAnimFromMemory Return type: Image Description: Load image sequence from memory buffer @@ -2776,60 +2781,60 @@ Function 293: LoadImageAnimFromMemory() (4 input parameters) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) Param[4]: frames (type: int *) -Function 294: LoadImageFromMemory() (3 input parameters) +Function 295: LoadImageFromMemory() (3 input parameters) Name: LoadImageFromMemory Return type: Image Description: Load image from memory buffer, fileType refers to extension: i.e. '.png' Param[1]: fileType (type: const char *) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 295: LoadImageFromTexture() (1 input parameters) +Function 296: LoadImageFromTexture() (1 input parameters) Name: LoadImageFromTexture Return type: Image Description: Load image from GPU texture data Param[1]: texture (type: Texture2D) -Function 296: LoadImageFromScreen() (0 input parameters) +Function 297: LoadImageFromScreen() (0 input parameters) Name: LoadImageFromScreen Return type: Image Description: Load image from screen buffer (screenshot) No input parameters -Function 297: IsImageValid() (1 input parameters) +Function 298: IsImageValid() (1 input parameters) Name: IsImageValid Return type: bool Description: Check if an image is valid (data and parameters) Param[1]: image (type: Image) -Function 298: UnloadImage() (1 input parameters) +Function 299: UnloadImage() (1 input parameters) Name: UnloadImage Return type: void Description: Unload image from CPU memory (RAM) Param[1]: image (type: Image) -Function 299: ExportImage() (2 input parameters) +Function 300: ExportImage() (2 input parameters) Name: ExportImage Return type: bool Description: Export image data to file, returns true on success Param[1]: image (type: Image) Param[2]: fileName (type: const char *) -Function 300: ExportImageToMemory() (3 input parameters) +Function 301: ExportImageToMemory() (3 input parameters) Name: ExportImageToMemory Return type: unsigned char * Description: Export image to memory buffer, memory must be MemFree() Param[1]: image (type: Image) Param[2]: fileType (type: const char *) Param[3]: fileSize (type: int *) -Function 301: ExportImageAsCode() (2 input parameters) +Function 302: ExportImageAsCode() (2 input parameters) Name: ExportImageAsCode Return type: bool Description: Export image as code file defining an array of bytes, returns true on success Param[1]: image (type: Image) Param[2]: fileName (type: const char *) -Function 302: GenImageColor() (3 input parameters) +Function 303: GenImageColor() (3 input parameters) Name: GenImageColor Return type: Image Description: Generate image: plain color Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: color (type: Color) -Function 303: GenImageGradientLinear() (5 input parameters) +Function 304: GenImageGradientLinear() (5 input parameters) Name: GenImageGradientLinear Return type: Image Description: Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient @@ -2838,7 +2843,7 @@ Function 303: GenImageGradientLinear() (5 input parameters) Param[3]: direction (type: int) Param[4]: start (type: Color) Param[5]: end (type: Color) -Function 304: GenImageGradientRadial() (5 input parameters) +Function 305: GenImageGradientRadial() (5 input parameters) Name: GenImageGradientRadial Return type: Image Description: Generate image: radial gradient @@ -2847,7 +2852,7 @@ Function 304: GenImageGradientRadial() (5 input parameters) Param[3]: density (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 305: GenImageGradientSquare() (5 input parameters) +Function 306: GenImageGradientSquare() (5 input parameters) Name: GenImageGradientSquare Return type: Image Description: Generate image: square gradient @@ -2856,7 +2861,7 @@ Function 305: GenImageGradientSquare() (5 input parameters) Param[3]: density (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 306: GenImageChecked() (6 input parameters) +Function 307: GenImageChecked() (6 input parameters) Name: GenImageChecked Return type: Image Description: Generate image: checked @@ -2866,14 +2871,14 @@ Function 306: GenImageChecked() (6 input parameters) Param[4]: checksY (type: int) Param[5]: col1 (type: Color) Param[6]: col2 (type: Color) -Function 307: GenImageWhiteNoise() (3 input parameters) +Function 308: GenImageWhiteNoise() (3 input parameters) Name: GenImageWhiteNoise Return type: Image Description: Generate image: white noise Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: factor (type: float) -Function 308: GenImagePerlinNoise() (5 input parameters) +Function 309: GenImagePerlinNoise() (5 input parameters) Name: GenImagePerlinNoise Return type: Image Description: Generate image: perlin noise @@ -2882,45 +2887,45 @@ Function 308: GenImagePerlinNoise() (5 input parameters) Param[3]: offsetX (type: int) Param[4]: offsetY (type: int) Param[5]: scale (type: float) -Function 309: GenImageCellular() (3 input parameters) +Function 310: GenImageCellular() (3 input parameters) Name: GenImageCellular Return type: Image Description: Generate image: cellular algorithm, bigger tileSize means bigger cells Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: tileSize (type: int) -Function 310: GenImageText() (3 input parameters) +Function 311: GenImageText() (3 input parameters) Name: GenImageText Return type: Image Description: Generate image: grayscale image from text data Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: text (type: const char *) -Function 311: ImageCopy() (1 input parameters) +Function 312: ImageCopy() (1 input parameters) Name: ImageCopy Return type: Image Description: Create an image duplicate (useful for transformations) Param[1]: image (type: Image) -Function 312: ImageFromImage() (2 input parameters) +Function 313: ImageFromImage() (2 input parameters) Name: ImageFromImage Return type: Image Description: Create an image from another image piece Param[1]: image (type: Image) Param[2]: rec (type: Rectangle) -Function 313: ImageFromChannel() (2 input parameters) +Function 314: ImageFromChannel() (2 input parameters) Name: ImageFromChannel Return type: Image Description: Create an image from a selected channel of another image (GRAYSCALE) Param[1]: image (type: Image) Param[2]: selectedChannel (type: int) -Function 314: ImageText() (3 input parameters) +Function 315: ImageText() (3 input parameters) Name: ImageText Return type: Image Description: Create an image from text (default font) Param[1]: text (type: const char *) Param[2]: fontSize (type: int) Param[3]: color (type: Color) -Function 315: ImageTextEx() (5 input parameters) +Function 316: ImageTextEx() (5 input parameters) Name: ImageTextEx Return type: Image Description: Create an image from text (custom sprite font) @@ -2929,76 +2934,76 @@ Function 315: ImageTextEx() (5 input parameters) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) Param[5]: tint (type: Color) -Function 316: ImageFormat() (2 input parameters) +Function 317: ImageFormat() (2 input parameters) Name: ImageFormat Return type: void Description: Convert image data to desired format Param[1]: image (type: Image *) Param[2]: newFormat (type: int) -Function 317: ImageToPOT() (2 input parameters) +Function 318: ImageToPOT() (2 input parameters) Name: ImageToPOT Return type: void Description: Convert image to POT (power-of-two) Param[1]: image (type: Image *) Param[2]: fill (type: Color) -Function 318: ImageCrop() (2 input parameters) +Function 319: ImageCrop() (2 input parameters) Name: ImageCrop Return type: void Description: Crop an image to a defined rectangle Param[1]: image (type: Image *) Param[2]: crop (type: Rectangle) -Function 319: ImageAlphaCrop() (2 input parameters) +Function 320: ImageAlphaCrop() (2 input parameters) Name: ImageAlphaCrop Return type: void Description: Crop image depending on alpha value Param[1]: image (type: Image *) Param[2]: threshold (type: float) -Function 320: ImageAlphaClear() (3 input parameters) +Function 321: ImageAlphaClear() (3 input parameters) Name: ImageAlphaClear Return type: void Description: Clear alpha channel to desired color Param[1]: image (type: Image *) Param[2]: color (type: Color) Param[3]: threshold (type: float) -Function 321: ImageAlphaMask() (2 input parameters) +Function 322: ImageAlphaMask() (2 input parameters) Name: ImageAlphaMask Return type: void Description: Apply alpha mask to image Param[1]: image (type: Image *) Param[2]: alphaMask (type: Image) -Function 322: ImageAlphaPremultiply() (1 input parameters) +Function 323: ImageAlphaPremultiply() (1 input parameters) Name: ImageAlphaPremultiply Return type: void Description: Premultiply alpha channel Param[1]: image (type: Image *) -Function 323: ImageBlurGaussian() (2 input parameters) +Function 324: ImageBlurGaussian() (2 input parameters) Name: ImageBlurGaussian Return type: void Description: Apply Gaussian blur using a box blur approximation Param[1]: image (type: Image *) Param[2]: blurSize (type: int) -Function 324: ImageKernelConvolution() (3 input parameters) +Function 325: ImageKernelConvolution() (3 input parameters) Name: ImageKernelConvolution Return type: void Description: Apply custom square convolution kernel to image Param[1]: image (type: Image *) Param[2]: kernel (type: const float *) Param[3]: kernelSize (type: int) -Function 325: ImageResize() (3 input parameters) +Function 326: ImageResize() (3 input parameters) Name: ImageResize Return type: void Description: Resize image (Bicubic scaling algorithm) Param[1]: image (type: Image *) Param[2]: newWidth (type: int) Param[3]: newHeight (type: int) -Function 326: ImageResizeNN() (3 input parameters) +Function 327: ImageResizeNN() (3 input parameters) Name: ImageResizeNN Return type: void Description: Resize image (Nearest-Neighbor scaling algorithm) Param[1]: image (type: Image *) Param[2]: newWidth (type: int) Param[3]: newHeight (type: int) -Function 327: ImageResizeCanvas() (6 input parameters) +Function 328: ImageResizeCanvas() (6 input parameters) Name: ImageResizeCanvas Return type: void Description: Resize canvas and fill with color @@ -3008,12 +3013,12 @@ Function 327: ImageResizeCanvas() (6 input parameters) Param[4]: offsetX (type: int) Param[5]: offsetY (type: int) Param[6]: fill (type: Color) -Function 328: ImageMipmaps() (1 input parameters) +Function 329: ImageMipmaps() (1 input parameters) Name: ImageMipmaps Return type: void Description: Compute all mipmap levels for a provided image Param[1]: image (type: Image *) -Function 329: ImageDither() (5 input parameters) +Function 330: ImageDither() (5 input parameters) Name: ImageDither Return type: void Description: Dither image data to 16bpp or lower (Floyd-Steinberg dithering) @@ -3022,109 +3027,109 @@ Function 329: ImageDither() (5 input parameters) Param[3]: gBpp (type: int) Param[4]: bBpp (type: int) Param[5]: aBpp (type: int) -Function 330: ImageFlipVertical() (1 input parameters) +Function 331: ImageFlipVertical() (1 input parameters) Name: ImageFlipVertical Return type: void Description: Flip image vertically Param[1]: image (type: Image *) -Function 331: ImageFlipHorizontal() (1 input parameters) +Function 332: ImageFlipHorizontal() (1 input parameters) Name: ImageFlipHorizontal Return type: void Description: Flip image horizontally Param[1]: image (type: Image *) -Function 332: ImageRotate() (2 input parameters) +Function 333: ImageRotate() (2 input parameters) Name: ImageRotate Return type: void Description: Rotate image by input angle in degrees (-359 to 359) Param[1]: image (type: Image *) Param[2]: degrees (type: int) -Function 333: ImageRotateCW() (1 input parameters) +Function 334: ImageRotateCW() (1 input parameters) Name: ImageRotateCW Return type: void Description: Rotate image clockwise 90deg Param[1]: image (type: Image *) -Function 334: ImageRotateCCW() (1 input parameters) +Function 335: ImageRotateCCW() (1 input parameters) Name: ImageRotateCCW Return type: void Description: Rotate image counter-clockwise 90deg Param[1]: image (type: Image *) -Function 335: ImageColorTint() (2 input parameters) +Function 336: ImageColorTint() (2 input parameters) Name: ImageColorTint Return type: void Description: Modify image color: tint Param[1]: image (type: Image *) Param[2]: color (type: Color) -Function 336: ImageColorInvert() (1 input parameters) +Function 337: ImageColorInvert() (1 input parameters) Name: ImageColorInvert Return type: void Description: Modify image color: invert Param[1]: image (type: Image *) -Function 337: ImageColorGrayscale() (1 input parameters) +Function 338: ImageColorGrayscale() (1 input parameters) Name: ImageColorGrayscale Return type: void Description: Modify image color: grayscale Param[1]: image (type: Image *) -Function 338: ImageColorContrast() (2 input parameters) +Function 339: ImageColorContrast() (2 input parameters) Name: ImageColorContrast Return type: void Description: Modify image color: contrast (-100 to 100) Param[1]: image (type: Image *) Param[2]: contrast (type: int) -Function 339: ImageColorBrightness() (2 input parameters) +Function 340: ImageColorBrightness() (2 input parameters) Name: ImageColorBrightness Return type: void Description: Modify image color: brightness (-255 to 255) Param[1]: image (type: Image *) Param[2]: brightness (type: int) -Function 340: ImageColorReplace() (3 input parameters) +Function 341: ImageColorReplace() (3 input parameters) Name: ImageColorReplace Return type: void Description: Modify image color: replace color Param[1]: image (type: Image *) Param[2]: color (type: Color) Param[3]: replace (type: Color) -Function 341: LoadImageColors() (1 input parameters) +Function 342: LoadImageColors() (1 input parameters) Name: LoadImageColors Return type: Color * Description: Load color data from image as a Color array (RGBA - 32bit) Param[1]: image (type: Image) -Function 342: LoadImagePalette() (3 input parameters) +Function 343: LoadImagePalette() (3 input parameters) Name: LoadImagePalette Return type: Color * Description: Load colors palette from image as a Color array (RGBA - 32bit) Param[1]: image (type: Image) Param[2]: maxPaletteSize (type: int) Param[3]: colorCount (type: int *) -Function 343: UnloadImageColors() (1 input parameters) +Function 344: UnloadImageColors() (1 input parameters) Name: UnloadImageColors Return type: void Description: Unload color data loaded with LoadImageColors() Param[1]: colors (type: Color *) -Function 344: UnloadImagePalette() (1 input parameters) +Function 345: UnloadImagePalette() (1 input parameters) Name: UnloadImagePalette Return type: void Description: Unload colors palette loaded with LoadImagePalette() Param[1]: colors (type: Color *) -Function 345: GetImageAlphaBorder() (2 input parameters) +Function 346: GetImageAlphaBorder() (2 input parameters) Name: GetImageAlphaBorder Return type: Rectangle Description: Get image alpha border rectangle Param[1]: image (type: Image) Param[2]: threshold (type: float) -Function 346: GetImageColor() (3 input parameters) +Function 347: GetImageColor() (3 input parameters) Name: GetImageColor Return type: Color Description: Get image pixel color at (x, y) position Param[1]: image (type: Image) Param[2]: x (type: int) Param[3]: y (type: int) -Function 347: ImageClearBackground() (2 input parameters) +Function 348: ImageClearBackground() (2 input parameters) Name: ImageClearBackground Return type: void Description: Clear image background with given color Param[1]: dst (type: Image *) Param[2]: color (type: Color) -Function 348: ImageDrawPixel() (4 input parameters) +Function 349: ImageDrawPixel() (4 input parameters) Name: ImageDrawPixel Return type: void Description: Draw pixel within an image @@ -3132,14 +3137,14 @@ Function 348: ImageDrawPixel() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: color (type: Color) -Function 349: ImageDrawPixelV() (3 input parameters) +Function 350: ImageDrawPixelV() (3 input parameters) Name: ImageDrawPixelV Return type: void Description: Draw pixel within an image (Vector version) Param[1]: dst (type: Image *) Param[2]: position (type: Vector2) Param[3]: color (type: Color) -Function 350: ImageDrawLine() (6 input parameters) +Function 351: ImageDrawLine() (6 input parameters) Name: ImageDrawLine Return type: void Description: Draw line within an image @@ -3149,7 +3154,7 @@ Function 350: ImageDrawLine() (6 input parameters) Param[4]: endPosX (type: int) Param[5]: endPosY (type: int) Param[6]: color (type: Color) -Function 351: ImageDrawLineV() (4 input parameters) +Function 352: ImageDrawLineV() (4 input parameters) Name: ImageDrawLineV Return type: void Description: Draw line within an image (Vector version) @@ -3157,7 +3162,7 @@ Function 351: ImageDrawLineV() (4 input parameters) Param[2]: start (type: Vector2) Param[3]: end (type: Vector2) Param[4]: color (type: Color) -Function 352: ImageDrawLineEx() (5 input parameters) +Function 353: ImageDrawLineEx() (5 input parameters) Name: ImageDrawLineEx Return type: void Description: Draw a line defining thickness within an image @@ -3166,7 +3171,7 @@ Function 352: ImageDrawLineEx() (5 input parameters) Param[3]: end (type: Vector2) Param[4]: thick (type: int) Param[5]: color (type: Color) -Function 353: ImageDrawLineStrip() (4 input parameters) +Function 354: ImageDrawLineStrip() (4 input parameters) Name: ImageDrawLineStrip Return type: void Description: Draw a lines sequence within an image @@ -3174,7 +3179,7 @@ Function 353: ImageDrawLineStrip() (4 input parameters) Param[2]: points (type: const Vector2 *) Param[3]: pointCount (type: int) Param[4]: color (type: Color) -Function 354: ImageDrawTriangle() (5 input parameters) +Function 355: ImageDrawTriangle() (5 input parameters) Name: ImageDrawTriangle Return type: void Description: Draw triangle within an image @@ -3183,7 +3188,7 @@ Function 354: ImageDrawTriangle() (5 input parameters) Param[3]: v2 (type: Vector2) Param[4]: v3 (type: Vector2) Param[5]: color (type: Color) -Function 355: ImageDrawTriangleGradient() (7 input parameters) +Function 356: ImageDrawTriangleGradient() (7 input parameters) Name: ImageDrawTriangleGradient Return type: void Description: Draw triangle with interpolated colors within an image @@ -3194,7 +3199,7 @@ Function 355: ImageDrawTriangleGradient() (7 input parameters) Param[5]: c1 (type: Color) Param[6]: c2 (type: Color) Param[7]: c3 (type: Color) -Function 356: ImageDrawTriangleLines() (5 input parameters) +Function 357: ImageDrawTriangleLines() (5 input parameters) Name: ImageDrawTriangleLines Return type: void Description: Draw triangle outline within an image @@ -3203,7 +3208,7 @@ Function 356: ImageDrawTriangleLines() (5 input parameters) Param[3]: v2 (type: Vector2) Param[4]: v3 (type: Vector2) Param[5]: color (type: Color) -Function 357: ImageDrawTriangleFan() (4 input parameters) +Function 358: ImageDrawTriangleFan() (4 input parameters) Name: ImageDrawTriangleFan Return type: void Description: Draw a triangle fan defined by points within an image (first vertex is the center) @@ -3211,7 +3216,7 @@ Function 357: ImageDrawTriangleFan() (4 input parameters) Param[2]: points (type: const Vector2 *) Param[3]: pointCount (type: int) Param[4]: color (type: Color) -Function 358: ImageDrawTriangleStrip() (4 input parameters) +Function 359: ImageDrawTriangleStrip() (4 input parameters) Name: ImageDrawTriangleStrip Return type: void Description: Draw a triangle strip defined by points within an image @@ -3219,7 +3224,7 @@ Function 358: ImageDrawTriangleStrip() (4 input parameters) Param[2]: points (type: const Vector2 *) Param[3]: pointCount (type: int) Param[4]: color (type: Color) -Function 359: ImageDrawRectangle() (6 input parameters) +Function 360: ImageDrawRectangle() (6 input parameters) Name: ImageDrawRectangle Return type: void Description: Draw rectangle within an image @@ -3229,7 +3234,7 @@ Function 359: ImageDrawRectangle() (6 input parameters) Param[4]: width (type: int) Param[5]: height (type: int) Param[6]: color (type: Color) -Function 360: ImageDrawRectangleV() (4 input parameters) +Function 361: ImageDrawRectangleV() (4 input parameters) Name: ImageDrawRectangleV Return type: void Description: Draw rectangle within an image (Vector version) @@ -3237,14 +3242,14 @@ Function 360: ImageDrawRectangleV() (4 input parameters) Param[2]: position (type: Vector2) Param[3]: size (type: Vector2) Param[4]: color (type: Color) -Function 361: ImageDrawRectangleRec() (3 input parameters) +Function 362: ImageDrawRectangleRec() (3 input parameters) Name: ImageDrawRectangleRec Return type: void Description: Draw rectangle within an image Param[1]: dst (type: Image *) Param[2]: rec (type: Rectangle) Param[3]: color (type: Color) -Function 362: ImageDrawRectanglePro() (5 input parameters) +Function 363: ImageDrawRectanglePro() (5 input parameters) Name: ImageDrawRectanglePro Return type: void Description: Draw a color-filled rectangle with pro parameters within and image @@ -3253,7 +3258,7 @@ Function 362: ImageDrawRectanglePro() (5 input parameters) Param[3]: origin (type: Vector2) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 363: ImageDrawRectangleLines() (6 input parameters) +Function 364: ImageDrawRectangleLines() (6 input parameters) Name: ImageDrawRectangleLines Return type: void Description: Draw rectangle lines within an image @@ -3263,7 +3268,7 @@ Function 363: ImageDrawRectangleLines() (6 input parameters) Param[4]: width (type: int) Param[5]: height (type: int) Param[6]: color (type: Color) -Function 364: ImageDrawRectangleLinesEx() (4 input parameters) +Function 365: ImageDrawRectangleLinesEx() (4 input parameters) Name: ImageDrawRectangleLinesEx Return type: void Description: Draw rectangle lines within an image with line thickness @@ -3271,7 +3276,7 @@ Function 364: ImageDrawRectangleLinesEx() (4 input parameters) Param[2]: rec (type: Rectangle) Param[3]: thick (type: int) Param[4]: color (type: Color) -Function 365: ImageDrawRectangleGradientEx() (6 input parameters) +Function 366: ImageDrawRectangleGradientEx() (6 input parameters) Name: ImageDrawRectangleGradientEx Return type: void Description: Draw rectangle with gradient colors within an image, counter-clockwise color order @@ -3281,7 +3286,7 @@ Function 365: ImageDrawRectangleGradientEx() (6 input parameters) Param[4]: col2 (type: Color) Param[5]: col3 (type: Color) Param[6]: col4 (type: Color) -Function 366: ImageDrawCircle() (5 input parameters) +Function 367: ImageDrawCircle() (5 input parameters) Name: ImageDrawCircle Return type: void Description: Draw a filled circle within an image @@ -3290,7 +3295,7 @@ Function 366: ImageDrawCircle() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 367: ImageDrawCircleV() (4 input parameters) +Function 368: ImageDrawCircleV() (4 input parameters) Name: ImageDrawCircleV Return type: void Description: Draw a filled circle within an image (Vector version) @@ -3298,7 +3303,7 @@ Function 367: ImageDrawCircleV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 368: ImageDrawCircleLines() (5 input parameters) +Function 369: ImageDrawCircleLines() (5 input parameters) Name: ImageDrawCircleLines Return type: void Description: Draw circle outline within an image @@ -3307,7 +3312,7 @@ Function 368: ImageDrawCircleLines() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 369: ImageDrawCircleLinesV() (4 input parameters) +Function 370: ImageDrawCircleLinesV() (4 input parameters) Name: ImageDrawCircleLinesV Return type: void Description: Draw circle outline within an image (Vector version) @@ -3315,7 +3320,7 @@ Function 369: ImageDrawCircleLinesV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 370: ImageDrawCircleGradient() (5 input parameters) +Function 371: ImageDrawCircleGradient() (5 input parameters) Name: ImageDrawCircleGradient Return type: void Description: Draw a gradient-filled circle within an image @@ -3324,7 +3329,7 @@ Function 370: ImageDrawCircleGradient() (5 input parameters) Param[3]: radius (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 371: ImageDrawImage() (5 input parameters) +Function 372: ImageDrawImage() (5 input parameters) Name: ImageDrawImage Return type: void Description: Draw an image within an image @@ -3333,7 +3338,7 @@ Function 371: ImageDrawImage() (5 input parameters) Param[3]: posX (type: int) Param[4]: posY (type: int) Param[5]: tint (type: Color) -Function 372: ImageDrawImageEx() (6 input parameters) +Function 373: ImageDrawImageEx() (6 input parameters) Name: ImageDrawImageEx Return type: void Description: Draw an image with scaling and rotation within an image @@ -3343,7 +3348,7 @@ Function 372: ImageDrawImageEx() (6 input parameters) Param[4]: rotation (type: float) Param[5]: scale (type: float) Param[6]: tint (type: Color) -Function 373: ImageDrawImageRec() (5 input parameters) +Function 374: ImageDrawImageRec() (5 input parameters) Name: ImageDrawImageRec Return type: void Description: Draw a part of an image defined by a rectangle within an image @@ -3352,7 +3357,7 @@ Function 373: ImageDrawImageRec() (5 input parameters) Param[3]: srcRec (type: Rectangle) Param[4]: position (type: Vector2) Param[5]: tint (type: Color) -Function 374: ImageDrawImagePro() (7 input parameters) +Function 375: ImageDrawImagePro() (7 input parameters) Name: ImageDrawImagePro Return type: void Description: Draw a part of an image defined by a rectangle into destination rectangle, with scaling and rotation, within an image @@ -3363,7 +3368,7 @@ Function 374: ImageDrawImagePro() (7 input parameters) Param[5]: origin (type: Vector2) Param[6]: rotation (type: float) Param[7]: tint (type: Color) -Function 375: ImageDrawText() (6 input parameters) +Function 376: ImageDrawText() (6 input parameters) Name: ImageDrawText Return type: void Description: Draw text (using default font) within an image (destination) @@ -3373,7 +3378,7 @@ Function 375: ImageDrawText() (6 input parameters) Param[4]: posY (type: int) Param[5]: fontSize (type: int) Param[6]: color (type: Color) -Function 376: ImageDrawTextEx() (7 input parameters) +Function 377: ImageDrawTextEx() (7 input parameters) Name: ImageDrawTextEx Return type: void Description: Draw text (custom sprite font) within an image (destination) @@ -3384,7 +3389,7 @@ Function 376: ImageDrawTextEx() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 377: ImageDrawTextPro() (9 input parameters) +Function 378: ImageDrawTextPro() (9 input parameters) Name: ImageDrawTextPro Return type: void Description: Draw text using Font and pro parameters (rotation) @@ -3397,79 +3402,79 @@ Function 377: ImageDrawTextPro() (9 input parameters) Param[7]: fontSize (type: float) Param[8]: spacing (type: float) Param[9]: tint (type: Color) -Function 378: LoadTexture() (1 input parameters) +Function 379: LoadTexture() (1 input parameters) Name: LoadTexture Return type: Texture2D Description: Load texture from file into GPU memory (VRAM) Param[1]: fileName (type: const char *) -Function 379: LoadTextureFromImage() (1 input parameters) +Function 380: LoadTextureFromImage() (1 input parameters) Name: LoadTextureFromImage Return type: Texture2D Description: Load texture from image data Param[1]: image (type: Image) -Function 380: LoadTextureCubemap() (2 input parameters) +Function 381: LoadTextureCubemap() (2 input parameters) Name: LoadTextureCubemap Return type: TextureCubemap Description: Load cubemap from image, multiple image cubemap layouts supported Param[1]: image (type: Image) Param[2]: layout (type: int) -Function 381: LoadRenderTexture() (2 input parameters) +Function 382: LoadRenderTexture() (2 input parameters) Name: LoadRenderTexture Return type: RenderTexture2D Description: Load texture for rendering (framebuffer) Param[1]: width (type: int) Param[2]: height (type: int) -Function 382: IsTextureValid() (1 input parameters) +Function 383: IsTextureValid() (1 input parameters) Name: IsTextureValid Return type: bool Description: Check if texture is valid (loaded in GPU) Param[1]: texture (type: Texture2D) -Function 383: UnloadTexture() (1 input parameters) +Function 384: UnloadTexture() (1 input parameters) Name: UnloadTexture Return type: void Description: Unload texture from GPU memory (VRAM) Param[1]: texture (type: Texture2D) -Function 384: IsRenderTextureValid() (1 input parameters) +Function 385: IsRenderTextureValid() (1 input parameters) Name: IsRenderTextureValid Return type: bool Description: Check if render texture is valid (loaded in GPU) Param[1]: target (type: RenderTexture2D) -Function 385: UnloadRenderTexture() (1 input parameters) +Function 386: UnloadRenderTexture() (1 input parameters) Name: UnloadRenderTexture Return type: void Description: Unload render texture from GPU memory (VRAM) Param[1]: target (type: RenderTexture2D) -Function 386: UpdateTexture() (2 input parameters) +Function 387: UpdateTexture() (2 input parameters) Name: UpdateTexture Return type: void Description: Update GPU texture with new data (pixels should be able to fill texture) Param[1]: texture (type: Texture2D) Param[2]: pixels (type: const void *) -Function 387: UpdateTextureRec() (3 input parameters) +Function 388: UpdateTextureRec() (3 input parameters) Name: UpdateTextureRec Return type: void Description: Update GPU texture rectangle with new data (pixels and rec should fit in texture) Param[1]: texture (type: Texture2D) Param[2]: rec (type: Rectangle) Param[3]: pixels (type: const void *) -Function 388: GenTextureMipmaps() (1 input parameters) +Function 389: GenTextureMipmaps() (1 input parameters) Name: GenTextureMipmaps Return type: void Description: Generate GPU mipmaps for a texture Param[1]: texture (type: Texture2D *) -Function 389: SetTextureFilter() (2 input parameters) +Function 390: SetTextureFilter() (2 input parameters) Name: SetTextureFilter Return type: void Description: Set texture scaling filter mode Param[1]: texture (type: Texture2D) Param[2]: filter (type: int) -Function 390: SetTextureWrap() (2 input parameters) +Function 391: SetTextureWrap() (2 input parameters) Name: SetTextureWrap Return type: void Description: Set texture wrapping mode Param[1]: texture (type: Texture2D) Param[2]: wrap (type: int) -Function 391: DrawTexture() (4 input parameters) +Function 392: DrawTexture() (4 input parameters) Name: DrawTexture Return type: void Description: Draw a Texture2D @@ -3477,14 +3482,14 @@ Function 391: DrawTexture() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: tint (type: Color) -Function 392: DrawTextureV() (3 input parameters) +Function 393: DrawTextureV() (3 input parameters) Name: DrawTextureV Return type: void Description: Draw a Texture2D with position defined as Vector2 Param[1]: texture (type: Texture2D) Param[2]: position (type: Vector2) Param[3]: tint (type: Color) -Function 393: DrawTextureEx() (5 input parameters) +Function 394: DrawTextureEx() (5 input parameters) Name: DrawTextureEx Return type: void Description: Draw a Texture2D with rotation and scale @@ -3493,7 +3498,7 @@ Function 393: DrawTextureEx() (5 input parameters) Param[3]: rotation (type: float) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 394: DrawTextureRec() (4 input parameters) +Function 395: DrawTextureRec() (4 input parameters) Name: DrawTextureRec Return type: void Description: Draw a part of a texture defined by a rectangle @@ -3501,7 +3506,7 @@ Function 394: DrawTextureRec() (4 input parameters) Param[2]: rec (type: Rectangle) Param[3]: position (type: Vector2) Param[4]: tint (type: Color) -Function 395: DrawTexturePro() (6 input parameters) +Function 396: DrawTexturePro() (6 input parameters) Name: DrawTexturePro Return type: void Description: Draw a part of a texture defined by a source rectangle to destination rectangle, with scaling and rotation @@ -3511,7 +3516,7 @@ Function 395: DrawTexturePro() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 396: DrawTextureNPatch() (6 input parameters) +Function 397: DrawTextureNPatch() (6 input parameters) Name: DrawTextureNPatch Return type: void Description: Draw a texture (or part of it) that stretches or shrinks nicely @@ -3521,119 +3526,119 @@ Function 396: DrawTextureNPatch() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 397: ColorIsEqual() (2 input parameters) +Function 398: ColorIsEqual() (2 input parameters) Name: ColorIsEqual Return type: bool Description: Check if two colors are equal Param[1]: col1 (type: Color) Param[2]: col2 (type: Color) -Function 398: Fade() (2 input parameters) +Function 399: Fade() (2 input parameters) Name: Fade Return type: Color Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f Param[1]: color (type: Color) Param[2]: alpha (type: float) -Function 399: ColorToInt() (1 input parameters) +Function 400: ColorToInt() (1 input parameters) Name: ColorToInt Return type: int Description: Get hexadecimal value for a Color (0xRRGGBBAA) Param[1]: color (type: Color) -Function 400: ColorNormalize() (1 input parameters) +Function 401: ColorNormalize() (1 input parameters) Name: ColorNormalize Return type: Vector4 Description: Get Color normalized as float [0..1] Param[1]: color (type: Color) -Function 401: ColorFromNormalized() (1 input parameters) +Function 402: ColorFromNormalized() (1 input parameters) Name: ColorFromNormalized Return type: Color Description: Get Color from normalized values [0..1] Param[1]: normalized (type: Vector4) -Function 402: ColorToHSV() (1 input parameters) +Function 403: ColorToHSV() (1 input parameters) Name: ColorToHSV Return type: Vector3 Description: Get HSV values for a Color, hue [0..360], saturation/value [0..1] Param[1]: color (type: Color) -Function 403: ColorFromHSV() (3 input parameters) +Function 404: ColorFromHSV() (3 input parameters) Name: ColorFromHSV Return type: Color Description: Get a Color from HSV values, hue [0..360], saturation/value [0..1] Param[1]: hue (type: float) Param[2]: saturation (type: float) Param[3]: value (type: float) -Function 404: ColorTint() (2 input parameters) +Function 405: ColorTint() (2 input parameters) Name: ColorTint Return type: Color Description: Get color multiplied with another color Param[1]: color (type: Color) Param[2]: tint (type: Color) -Function 405: ColorBrightness() (2 input parameters) +Function 406: ColorBrightness() (2 input parameters) Name: ColorBrightness Return type: Color Description: Get color with brightness correction, brightness factor goes from -1.0f to 1.0f Param[1]: color (type: Color) Param[2]: factor (type: float) -Function 406: ColorContrast() (2 input parameters) +Function 407: ColorContrast() (2 input parameters) Name: ColorContrast Return type: Color Description: Get color with contrast correction, contrast values between -1.0f and 1.0f Param[1]: color (type: Color) Param[2]: contrast (type: float) -Function 407: ColorAlpha() (2 input parameters) +Function 408: ColorAlpha() (2 input parameters) Name: ColorAlpha Return type: Color Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f Param[1]: color (type: Color) Param[2]: alpha (type: float) -Function 408: ColorAlphaBlend() (3 input parameters) +Function 409: ColorAlphaBlend() (3 input parameters) Name: ColorAlphaBlend Return type: Color Description: Get src alpha-blended into dst color with tint Param[1]: dst (type: Color) Param[2]: src (type: Color) Param[3]: tint (type: Color) -Function 409: ColorLerp() (3 input parameters) +Function 410: ColorLerp() (3 input parameters) Name: ColorLerp Return type: Color Description: Get color lerp interpolation between two colors, factor [0.0f..1.0f] Param[1]: color1 (type: Color) Param[2]: color2 (type: Color) Param[3]: factor (type: float) -Function 410: GetColor() (1 input parameters) +Function 411: GetColor() (1 input parameters) Name: GetColor Return type: Color Description: Get Color structure from hexadecimal value Param[1]: hexValue (type: unsigned int) -Function 411: GetPixelColor() (2 input parameters) +Function 412: GetPixelColor() (2 input parameters) Name: GetPixelColor Return type: Color Description: Get Color from a source pixel pointer of certain format Param[1]: srcPtr (type: const void *) Param[2]: format (type: int) -Function 412: SetPixelColor() (3 input parameters) +Function 413: SetPixelColor() (3 input parameters) Name: SetPixelColor Return type: void Description: Set color formatted into destination pixel pointer Param[1]: dstPtr (type: void *) Param[2]: color (type: Color) Param[3]: format (type: int) -Function 413: GetPixelDataSize() (3 input parameters) +Function 414: GetPixelDataSize() (3 input parameters) Name: GetPixelDataSize Return type: int Description: Get pixel data size in bytes for certain format Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: format (type: int) -Function 414: GetFontDefault() (0 input parameters) +Function 415: GetFontDefault() (0 input parameters) Name: GetFontDefault Return type: Font Description: Get the default Font No input parameters -Function 415: LoadFont() (1 input parameters) +Function 416: LoadFont() (1 input parameters) Name: LoadFont Return type: Font Description: Load font from file into GPU memory (VRAM) Param[1]: fileName (type: const char *) -Function 416: LoadFontEx() (4 input parameters) +Function 417: LoadFontEx() (4 input parameters) Name: LoadFontEx Return type: Font Description: Load font from file with defined codepoints and generation size, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height @@ -3641,14 +3646,14 @@ Function 416: LoadFontEx() (4 input parameters) Param[2]: fontSize (type: int) Param[3]: codepoints (type: const int *) Param[4]: codepointCount (type: int) -Function 417: LoadFontFromImage() (3 input parameters) +Function 418: LoadFontFromImage() (3 input parameters) Name: LoadFontFromImage Return type: Font Description: Load font from Image (XNA style) Param[1]: image (type: Image) Param[2]: key (type: Color) Param[3]: firstChar (type: int) -Function 418: LoadFontFromMemory() (6 input parameters) +Function 419: LoadFontFromMemory() (6 input parameters) Name: LoadFontFromMemory Return type: Font Description: Load font from memory buffer, fileType refers to extension: i.e. '.ttf' @@ -3658,12 +3663,12 @@ Function 418: LoadFontFromMemory() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: codepoints (type: const int *) Param[6]: codepointCount (type: int) -Function 419: IsFontValid() (1 input parameters) +Function 420: IsFontValid() (1 input parameters) Name: IsFontValid Return type: bool Description: Check if font is valid (font data loaded, WARNING: GPU texture not checked) Param[1]: font (type: Font) -Function 420: LoadFontData() (7 input parameters) +Function 421: LoadFontData() (7 input parameters) Name: LoadFontData Return type: GlyphInfo * Description: Load font data for further use @@ -3674,7 +3679,7 @@ Function 420: LoadFontData() (7 input parameters) Param[5]: codepointCount (type: int) Param[6]: type (type: int) Param[7]: glyphCount (type: int *) -Function 421: GenImageFontAtlas() (6 input parameters) +Function 422: GenImageFontAtlas() (6 input parameters) Name: GenImageFontAtlas Return type: Image Description: Generate image font atlas using chars info @@ -3684,30 +3689,30 @@ Function 421: GenImageFontAtlas() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: padding (type: int) Param[6]: packMethod (type: int) -Function 422: UnloadFontData() (2 input parameters) +Function 423: UnloadFontData() (2 input parameters) Name: UnloadFontData Return type: void Description: Unload font chars info data (RAM) Param[1]: glyphs (type: GlyphInfo *) Param[2]: glyphCount (type: int) -Function 423: UnloadFont() (1 input parameters) +Function 424: UnloadFont() (1 input parameters) Name: UnloadFont Return type: void Description: Unload font from GPU memory (VRAM) Param[1]: font (type: Font) -Function 424: ExportFontAsCode() (2 input parameters) +Function 425: ExportFontAsCode() (2 input parameters) Name: ExportFontAsCode Return type: bool Description: Export font as code file, returns true on success Param[1]: font (type: Font) Param[2]: fileName (type: const char *) -Function 425: DrawFPS() (2 input parameters) +Function 426: DrawFPS() (2 input parameters) Name: DrawFPS Return type: void Description: Draw current FPS Param[1]: posX (type: int) Param[2]: posY (type: int) -Function 426: DrawText() (5 input parameters) +Function 427: DrawText() (5 input parameters) Name: DrawText Return type: void Description: Draw text (using default font) @@ -3716,7 +3721,7 @@ Function 426: DrawText() (5 input parameters) Param[3]: posY (type: int) Param[4]: fontSize (type: int) Param[5]: color (type: Color) -Function 427: DrawTextEx() (6 input parameters) +Function 428: DrawTextEx() (6 input parameters) Name: DrawTextEx Return type: void Description: Draw text using font and additional parameters @@ -3726,7 +3731,7 @@ Function 427: DrawTextEx() (6 input parameters) Param[4]: fontSize (type: float) Param[5]: spacing (type: float) Param[6]: tint (type: Color) -Function 428: DrawTextPro() (8 input parameters) +Function 429: DrawTextPro() (8 input parameters) Name: DrawTextPro Return type: void Description: Draw text using Font and pro parameters (rotation) @@ -3738,7 +3743,7 @@ Function 428: DrawTextPro() (8 input parameters) Param[6]: fontSize (type: float) Param[7]: spacing (type: float) Param[8]: tint (type: Color) -Function 429: DrawTextCodepoint() (5 input parameters) +Function 430: DrawTextCodepoint() (5 input parameters) Name: DrawTextCodepoint Return type: void Description: Draw one character (codepoint) @@ -3747,7 +3752,7 @@ Function 429: DrawTextCodepoint() (5 input parameters) Param[3]: position (type: Vector2) Param[4]: fontSize (type: float) Param[5]: tint (type: Color) -Function 430: DrawTextCodepoints() (7 input parameters) +Function 431: DrawTextCodepoints() (7 input parameters) Name: DrawTextCodepoints Return type: void Description: Draw multiple characters (codepoint) @@ -3758,18 +3763,18 @@ Function 430: DrawTextCodepoints() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 431: SetTextLineSpacing() (1 input parameters) +Function 432: SetTextLineSpacing() (1 input parameters) Name: SetTextLineSpacing Return type: void Description: Set vertical line spacing when drawing with line-breaks Param[1]: spacing (type: int) -Function 432: MeasureText() (2 input parameters) +Function 433: MeasureText() (2 input parameters) Name: MeasureText Return type: int Description: Measure string width for default font Param[1]: text (type: const char *) Param[2]: fontSize (type: int) -Function 433: MeasureTextEx() (4 input parameters) +Function 434: MeasureTextEx() (4 input parameters) Name: MeasureTextEx Return type: Vector2 Description: Measure string size for Font @@ -3777,7 +3782,7 @@ Function 433: MeasureTextEx() (4 input parameters) Param[2]: text (type: const char *) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) -Function 434: MeasureTextCodepoints() (5 input parameters) +Function 435: MeasureTextCodepoints() (5 input parameters) Name: MeasureTextCodepoints Return type: Vector2 Description: Measure string size for an existing array of codepoints for Font @@ -3786,144 +3791,144 @@ Function 434: MeasureTextCodepoints() (5 input parameters) Param[3]: length (type: int) Param[4]: fontSize (type: float) Param[5]: spacing (type: float) -Function 435: GetGlyphIndex() (2 input parameters) +Function 436: GetGlyphIndex() (2 input parameters) Name: GetGlyphIndex Return type: int Description: Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found Param[1]: font (type: Font) Param[2]: codepoint (type: int) -Function 436: GetGlyphInfo() (2 input parameters) +Function 437: GetGlyphInfo() (2 input parameters) Name: GetGlyphInfo Return type: GlyphInfo Description: Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found Param[1]: font (type: Font) Param[2]: codepoint (type: int) -Function 437: GetGlyphAtlasRec() (2 input parameters) +Function 438: GetGlyphAtlasRec() (2 input parameters) Name: GetGlyphAtlasRec Return type: Rectangle Description: Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found Param[1]: font (type: Font) Param[2]: codepoint (type: int) -Function 438: LoadUTF8() (2 input parameters) +Function 439: LoadUTF8() (2 input parameters) Name: LoadUTF8 Return type: char * Description: Load UTF-8 text encoded from codepoints array Param[1]: codepoints (type: const int *) Param[2]: length (type: int) -Function 439: UnloadUTF8() (1 input parameters) +Function 440: UnloadUTF8() (1 input parameters) Name: UnloadUTF8 Return type: void Description: Unload UTF-8 text encoded from codepoints array Param[1]: text (type: char *) -Function 440: LoadCodepoints() (2 input parameters) +Function 441: LoadCodepoints() (2 input parameters) Name: LoadCodepoints Return type: int * Description: Load all codepoints from a UTF-8 text string, codepoints count returned by parameter Param[1]: text (type: const char *) Param[2]: count (type: int *) -Function 441: UnloadCodepoints() (1 input parameters) +Function 442: UnloadCodepoints() (1 input parameters) Name: UnloadCodepoints Return type: void Description: Unload codepoints data from memory Param[1]: codepoints (type: int *) -Function 442: GetCodepointCount() (1 input parameters) +Function 443: GetCodepointCount() (1 input parameters) Name: GetCodepointCount Return type: int Description: Get total number of codepoints in a UTF-8 encoded string Param[1]: text (type: const char *) -Function 443: GetCodepoint() (2 input parameters) +Function 444: GetCodepoint() (2 input parameters) Name: GetCodepoint Return type: int Description: Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure Param[1]: text (type: const char *) Param[2]: codepointSize (type: int *) -Function 444: GetCodepointNext() (2 input parameters) +Function 445: GetCodepointNext() (2 input parameters) Name: GetCodepointNext Return type: int Description: Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure Param[1]: text (type: const char *) Param[2]: codepointSize (type: int *) -Function 445: GetCodepointPrevious() (2 input parameters) +Function 446: GetCodepointPrevious() (2 input parameters) Name: GetCodepointPrevious Return type: int Description: Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure Param[1]: text (type: const char *) Param[2]: codepointSize (type: int *) -Function 446: CodepointToUTF8() (2 input parameters) +Function 447: CodepointToUTF8() (2 input parameters) Name: CodepointToUTF8 Return type: const char * Description: Encode one codepoint into UTF-8 byte array (array length returned as parameter) Param[1]: codepoint (type: int) Param[2]: utf8Size (type: int *) -Function 447: LoadTextLines() (2 input parameters) +Function 448: LoadTextLines() (2 input parameters) Name: LoadTextLines Return type: char ** Description: Load text as separate lines ('\n') Param[1]: text (type: const char *) Param[2]: count (type: int *) -Function 448: UnloadTextLines() (2 input parameters) +Function 449: UnloadTextLines() (2 input parameters) Name: UnloadTextLines Return type: void Description: Unload text lines Param[1]: text (type: char **) Param[2]: lineCount (type: int) -Function 449: TextCopy() (2 input parameters) +Function 450: TextCopy() (2 input parameters) Name: TextCopy Return type: int Description: Copy one string to another, returns bytes copied Param[1]: dst (type: char *) Param[2]: src (type: const char *) -Function 450: TextIsEqual() (2 input parameters) +Function 451: TextIsEqual() (2 input parameters) Name: TextIsEqual Return type: bool Description: Check if two text strings are equal Param[1]: text1 (type: const char *) Param[2]: text2 (type: const char *) -Function 451: TextLength() (1 input parameters) +Function 452: TextLength() (1 input parameters) Name: TextLength Return type: unsigned int Description: Get text length, checks for '\0' ending Param[1]: text (type: const char *) -Function 452: TextFormat() (2 input parameters) +Function 453: TextFormat() (2 input parameters) Name: TextFormat Return type: const char * Description: Text formatting with variables (sprintf() style) Param[1]: text (type: const char *) Param[2]: args (type: ...) -Function 453: TextSubtext() (3 input parameters) +Function 454: TextSubtext() (3 input parameters) Name: TextSubtext Return type: const char * Description: Get a piece of a text string Param[1]: text (type: const char *) Param[2]: position (type: int) Param[3]: length (type: int) -Function 454: TextRemoveSpaces() (1 input parameters) +Function 455: TextRemoveSpaces() (1 input parameters) Name: TextRemoveSpaces Return type: const char * Description: Remove text spaces, concat words Param[1]: text (type: const char *) -Function 455: GetTextBetween() (3 input parameters) +Function 456: GetTextBetween() (3 input parameters) Name: GetTextBetween Return type: char * Description: Get text between two strings Param[1]: text (type: const char *) Param[2]: begin (type: const char *) Param[3]: end (type: const char *) -Function 456: TextReplace() (3 input parameters) +Function 457: TextReplace() (3 input parameters) Name: TextReplace Return type: char * Description: Replace text string with new string Param[1]: text (type: const char *) Param[2]: search (type: const char *) Param[3]: replacement (type: const char *) -Function 457: TextReplaceAlloc() (3 input parameters) +Function 458: TextReplaceAlloc() (3 input parameters) Name: TextReplaceAlloc Return type: char * Description: Replace text string with new string, memory must be MemFree() Param[1]: text (type: const char *) Param[2]: search (type: const char *) Param[3]: replacement (type: const char *) -Function 458: TextReplaceBetween() (4 input parameters) +Function 459: TextReplaceBetween() (4 input parameters) Name: TextReplaceBetween Return type: char * Description: Replace text between two specific strings @@ -3931,7 +3936,7 @@ Function 458: TextReplaceBetween() (4 input parameters) Param[2]: begin (type: const char *) Param[3]: end (type: const char *) Param[4]: replacement (type: const char *) -Function 459: TextReplaceBetweenAlloc() (4 input parameters) +Function 460: TextReplaceBetweenAlloc() (4 input parameters) Name: TextReplaceBetweenAlloc Return type: char * Description: Replace text between two specific strings, memory must be MemFree() @@ -3939,96 +3944,96 @@ Function 459: TextReplaceBetweenAlloc() (4 input parameters) Param[2]: begin (type: const char *) Param[3]: end (type: const char *) Param[4]: replacement (type: const char *) -Function 460: TextInsert() (3 input parameters) +Function 461: TextInsert() (3 input parameters) Name: TextInsert Return type: char * Description: Insert text in a defined byte position Param[1]: text (type: const char *) Param[2]: insert (type: const char *) Param[3]: position (type: int) -Function 461: TextInsertAlloc() (3 input parameters) +Function 462: TextInsertAlloc() (3 input parameters) Name: TextInsertAlloc Return type: char * Description: Insert text in a defined byte position, memory must be MemFree() Param[1]: text (type: const char *) Param[2]: insert (type: const char *) Param[3]: position (type: int) -Function 462: TextJoin() (3 input parameters) +Function 463: TextJoin() (3 input parameters) Name: TextJoin Return type: char * Description: Join text strings with delimiter Param[1]: textList (type: char **) Param[2]: count (type: int) Param[3]: delimiter (type: const char *) -Function 463: TextSplit() (3 input parameters) +Function 464: TextSplit() (3 input parameters) Name: TextSplit Return type: char ** Description: Split text into multiple strings, using MAX_TEXTSPLIT_COUNT static strings Param[1]: text (type: const char *) Param[2]: delimiter (type: char) Param[3]: count (type: int *) -Function 464: TextAppend() (3 input parameters) +Function 465: TextAppend() (3 input parameters) Name: TextAppend Return type: void Description: Append text at specific position and move cursor Param[1]: text (type: char *) Param[2]: append (type: const char *) Param[3]: position (type: int *) -Function 465: TextFindIndex() (2 input parameters) +Function 466: TextFindIndex() (2 input parameters) Name: TextFindIndex Return type: int Description: Find first text occurrence within a string, -1 if not found Param[1]: text (type: const char *) Param[2]: search (type: const char *) -Function 466: TextToUpper() (1 input parameters) +Function 467: TextToUpper() (1 input parameters) Name: TextToUpper Return type: char * Description: Get upper case version of provided string Param[1]: text (type: const char *) -Function 467: TextToLower() (1 input parameters) +Function 468: TextToLower() (1 input parameters) Name: TextToLower Return type: char * Description: Get lower case version of provided string Param[1]: text (type: const char *) -Function 468: TextToPascal() (1 input parameters) +Function 469: TextToPascal() (1 input parameters) Name: TextToPascal Return type: char * Description: Get Pascal case notation version of provided string Param[1]: text (type: const char *) -Function 469: TextToSnake() (1 input parameters) +Function 470: TextToSnake() (1 input parameters) Name: TextToSnake Return type: char * Description: Get Snake case notation version of provided string Param[1]: text (type: const char *) -Function 470: TextToCamel() (1 input parameters) +Function 471: TextToCamel() (1 input parameters) Name: TextToCamel Return type: char * Description: Get Camel case notation version of provided string Param[1]: text (type: const char *) -Function 471: TextToInteger() (1 input parameters) +Function 472: TextToInteger() (1 input parameters) Name: TextToInteger Return type: int Description: Get integer value from text Param[1]: text (type: const char *) -Function 472: TextToFloat() (1 input parameters) +Function 473: TextToFloat() (1 input parameters) Name: TextToFloat Return type: float Description: Get float value from text Param[1]: text (type: const char *) -Function 473: DrawLine3D() (3 input parameters) +Function 474: DrawLine3D() (3 input parameters) Name: DrawLine3D Return type: void Description: Draw a line in 3D world space Param[1]: startPos (type: Vector3) Param[2]: endPos (type: Vector3) Param[3]: color (type: Color) -Function 474: DrawPoint3D() (2 input parameters) +Function 475: DrawPoint3D() (2 input parameters) Name: DrawPoint3D Return type: void Description: Draw a point in 3D space, actually a small line Param[1]: position (type: Vector3) Param[2]: color (type: Color) -Function 475: DrawCircle3D() (5 input parameters) +Function 476: DrawCircle3D() (5 input parameters) Name: DrawCircle3D Return type: void Description: Draw a circle in 3D world space @@ -4037,7 +4042,7 @@ Function 475: DrawCircle3D() (5 input parameters) Param[3]: rotationAxis (type: Vector3) Param[4]: rotationAngle (type: float) Param[5]: color (type: Color) -Function 476: DrawTriangle3D() (4 input parameters) +Function 477: DrawTriangle3D() (4 input parameters) Name: DrawTriangle3D Return type: void Description: Draw a color-filled triangle, counter-clockwise vertex order @@ -4045,14 +4050,14 @@ Function 476: DrawTriangle3D() (4 input parameters) Param[2]: v2 (type: Vector3) Param[3]: v3 (type: Vector3) Param[4]: color (type: Color) -Function 477: DrawTriangleStrip3D() (3 input parameters) +Function 478: DrawTriangleStrip3D() (3 input parameters) Name: DrawTriangleStrip3D Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: const Vector3 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 478: DrawCube() (5 input parameters) +Function 479: DrawCube() (5 input parameters) Name: DrawCube Return type: void Description: Draw cube @@ -4061,14 +4066,14 @@ Function 478: DrawCube() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 479: DrawCubeV() (3 input parameters) +Function 480: DrawCubeV() (3 input parameters) Name: DrawCubeV Return type: void Description: Draw cube (Vector version) Param[1]: position (type: Vector3) Param[2]: size (type: Vector3) Param[3]: color (type: Color) -Function 480: DrawCubeWires() (5 input parameters) +Function 481: DrawCubeWires() (5 input parameters) Name: DrawCubeWires Return type: void Description: Draw cube wires @@ -4077,21 +4082,21 @@ Function 480: DrawCubeWires() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 481: DrawCubeWiresV() (3 input parameters) +Function 482: DrawCubeWiresV() (3 input parameters) Name: DrawCubeWiresV Return type: void Description: Draw cube wires (Vector version) Param[1]: position (type: Vector3) Param[2]: size (type: Vector3) Param[3]: color (type: Color) -Function 482: DrawSphere() (3 input parameters) +Function 483: DrawSphere() (3 input parameters) Name: DrawSphere Return type: void Description: Draw sphere Param[1]: centerPos (type: Vector3) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 483: DrawSphereEx() (5 input parameters) +Function 484: DrawSphereEx() (5 input parameters) Name: DrawSphereEx Return type: void Description: Draw sphere with defined rings and slices @@ -4100,7 +4105,7 @@ Function 483: DrawSphereEx() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 484: DrawSphereWires() (5 input parameters) +Function 485: DrawSphereWires() (5 input parameters) Name: DrawSphereWires Return type: void Description: Draw sphere wires @@ -4109,7 +4114,7 @@ Function 484: DrawSphereWires() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 485: DrawCylinder() (6 input parameters) +Function 486: DrawCylinder() (6 input parameters) Name: DrawCylinder Return type: void Description: Draw a cylinder/cone @@ -4119,7 +4124,7 @@ Function 485: DrawCylinder() (6 input parameters) Param[4]: height (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 486: DrawCylinderEx() (6 input parameters) +Function 487: DrawCylinderEx() (6 input parameters) Name: DrawCylinderEx Return type: void Description: Draw a cylinder with base at startPos and top at endPos @@ -4129,7 +4134,7 @@ Function 486: DrawCylinderEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 487: DrawCylinderWires() (6 input parameters) +Function 488: DrawCylinderWires() (6 input parameters) Name: DrawCylinderWires Return type: void Description: Draw a cylinder/cone wires @@ -4139,7 +4144,7 @@ Function 487: DrawCylinderWires() (6 input parameters) Param[4]: height (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 488: DrawCylinderWiresEx() (6 input parameters) +Function 489: DrawCylinderWiresEx() (6 input parameters) Name: DrawCylinderWiresEx Return type: void Description: Draw a cylinder wires with base at startPos and top at endPos @@ -4149,7 +4154,7 @@ Function 488: DrawCylinderWiresEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 489: DrawCapsule() (6 input parameters) +Function 490: DrawCapsule() (6 input parameters) Name: DrawCapsule Return type: void Description: Draw a capsule with the center of its sphere caps at startPos and endPos @@ -4159,7 +4164,7 @@ Function 489: DrawCapsule() (6 input parameters) Param[4]: rings (type: int) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 490: DrawCapsuleWires() (6 input parameters) +Function 491: DrawCapsuleWires() (6 input parameters) Name: DrawCapsuleWires Return type: void Description: Draw capsule wireframe with the center of its sphere caps at startPos and endPos @@ -4169,51 +4174,51 @@ Function 490: DrawCapsuleWires() (6 input parameters) Param[4]: rings (type: int) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 491: DrawPlane() (3 input parameters) +Function 492: DrawPlane() (3 input parameters) Name: DrawPlane Return type: void Description: Draw a plane XZ Param[1]: centerPos (type: Vector3) Param[2]: size (type: Vector2) Param[3]: color (type: Color) -Function 492: DrawRay() (2 input parameters) +Function 493: DrawRay() (2 input parameters) Name: DrawRay Return type: void Description: Draw a ray line Param[1]: ray (type: Ray) Param[2]: color (type: Color) -Function 493: DrawGrid() (2 input parameters) +Function 494: DrawGrid() (2 input parameters) Name: DrawGrid Return type: void Description: Draw a grid (centered at (0, 0, 0)) Param[1]: slices (type: int) Param[2]: spacing (type: float) -Function 494: LoadModel() (1 input parameters) +Function 495: LoadModel() (1 input parameters) Name: LoadModel Return type: Model Description: Load model from files (meshes and materials) Param[1]: fileName (type: const char *) -Function 495: LoadModelFromMesh() (1 input parameters) +Function 496: LoadModelFromMesh() (1 input parameters) Name: LoadModelFromMesh Return type: Model Description: Load model from generated mesh (default material) Param[1]: mesh (type: Mesh) -Function 496: IsModelValid() (1 input parameters) +Function 497: IsModelValid() (1 input parameters) Name: IsModelValid Return type: bool Description: Check if model is valid (loaded in GPU, VAO/VBOs) Param[1]: model (type: Model) -Function 497: UnloadModel() (1 input parameters) +Function 498: UnloadModel() (1 input parameters) Name: UnloadModel Return type: void Description: Unload model (including meshes) from memory (RAM and/or VRAM) Param[1]: model (type: Model) -Function 498: GetModelBoundingBox() (1 input parameters) +Function 499: GetModelBoundingBox() (1 input parameters) Name: GetModelBoundingBox Return type: BoundingBox Description: Compute model bounding box limits (considers all meshes) Param[1]: model (type: Model) -Function 499: DrawModel() (4 input parameters) +Function 500: DrawModel() (4 input parameters) Name: DrawModel Return type: void Description: Draw a model (with texture if set) @@ -4221,7 +4226,7 @@ Function 499: DrawModel() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 500: DrawModelEx() (6 input parameters) +Function 501: DrawModelEx() (6 input parameters) Name: DrawModelEx Return type: void Description: Draw a model with custom transform @@ -4231,7 +4236,7 @@ Function 500: DrawModelEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 501: DrawModelWires() (4 input parameters) +Function 502: DrawModelWires() (4 input parameters) Name: DrawModelWires Return type: void Description: Draw a model wires (with texture if set) @@ -4239,7 +4244,7 @@ Function 501: DrawModelWires() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 502: DrawModelWiresEx() (6 input parameters) +Function 503: DrawModelWiresEx() (6 input parameters) Name: DrawModelWiresEx Return type: void Description: Draw a model wires with custom transform @@ -4249,13 +4254,13 @@ Function 502: DrawModelWiresEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 503: DrawBoundingBox() (2 input parameters) +Function 504: DrawBoundingBox() (2 input parameters) Name: DrawBoundingBox Return type: void Description: Draw bounding box (wires) Param[1]: box (type: BoundingBox) Param[2]: color (type: Color) -Function 504: DrawBillboard() (5 input parameters) +Function 505: DrawBillboard() (5 input parameters) Name: DrawBillboard Return type: void Description: Draw a billboard texture @@ -4264,7 +4269,7 @@ Function 504: DrawBillboard() (5 input parameters) Param[3]: position (type: Vector3) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 505: DrawBillboardRec() (6 input parameters) +Function 506: DrawBillboardRec() (6 input parameters) Name: DrawBillboardRec Return type: void Description: Draw a billboard texture defined by rectangle @@ -4274,7 +4279,7 @@ Function 505: DrawBillboardRec() (6 input parameters) Param[4]: position (type: Vector3) Param[5]: size (type: Vector2) Param[6]: tint (type: Color) -Function 506: DrawBillboardPro() (9 input parameters) +Function 507: DrawBillboardPro() (9 input parameters) Name: DrawBillboardPro Return type: void Description: Draw a billboard texture defined by source rectangle with scaling and rotation @@ -4287,13 +4292,13 @@ Function 506: DrawBillboardPro() (9 input parameters) Param[7]: origin (type: Vector2) Param[8]: rotation (type: float) Param[9]: tint (type: Color) -Function 507: UploadMesh() (2 input parameters) +Function 508: UploadMesh() (2 input parameters) Name: UploadMesh Return type: void Description: Upload mesh vertex data in GPU and provide VAO/VBO ids Param[1]: mesh (type: Mesh *) Param[2]: dynamic (type: bool) -Function 508: UpdateMeshBuffer() (5 input parameters) +Function 509: UpdateMeshBuffer() (5 input parameters) Name: UpdateMeshBuffer Return type: void Description: Update mesh vertex data in GPU for a specific buffer index @@ -4302,19 +4307,19 @@ Function 508: UpdateMeshBuffer() (5 input parameters) Param[3]: data (type: const void *) Param[4]: dataSize (type: int) Param[5]: offset (type: int) -Function 509: UnloadMesh() (1 input parameters) +Function 510: UnloadMesh() (1 input parameters) Name: UnloadMesh Return type: void Description: Unload mesh data from CPU and GPU Param[1]: mesh (type: Mesh) -Function 510: DrawMesh() (3 input parameters) +Function 511: DrawMesh() (3 input parameters) Name: DrawMesh Return type: void Description: Draw a 3d mesh with material and transform Param[1]: mesh (type: Mesh) Param[2]: material (type: Material) Param[3]: transform (type: Matrix) -Function 511: DrawMeshInstanced() (4 input parameters) +Function 512: DrawMeshInstanced() (4 input parameters) Name: DrawMeshInstanced Return type: void Description: Draw multiple mesh instances with material and different transforms @@ -4322,35 +4327,35 @@ Function 511: DrawMeshInstanced() (4 input parameters) Param[2]: material (type: Material) Param[3]: transforms (type: const Matrix *) Param[4]: instances (type: int) -Function 512: GetMeshBoundingBox() (1 input parameters) +Function 513: GetMeshBoundingBox() (1 input parameters) Name: GetMeshBoundingBox Return type: BoundingBox Description: Compute mesh bounding box limits Param[1]: mesh (type: Mesh) -Function 513: GenMeshTangents() (1 input parameters) +Function 514: GenMeshTangents() (1 input parameters) Name: GenMeshTangents Return type: void Description: Compute mesh tangents Param[1]: mesh (type: Mesh *) -Function 514: ExportMesh() (2 input parameters) +Function 515: ExportMesh() (2 input parameters) Name: ExportMesh Return type: bool Description: Export mesh data to file, returns true on success Param[1]: mesh (type: Mesh) Param[2]: fileName (type: const char *) -Function 515: ExportMeshAsCode() (2 input parameters) +Function 516: ExportMeshAsCode() (2 input parameters) Name: ExportMeshAsCode Return type: bool Description: Export mesh as code file (.h) defining multiple arrays of vertex attributes Param[1]: mesh (type: Mesh) Param[2]: fileName (type: const char *) -Function 516: GenMeshPoly() (2 input parameters) +Function 517: GenMeshPoly() (2 input parameters) Name: GenMeshPoly Return type: Mesh Description: Generate polygonal mesh Param[1]: sides (type: int) Param[2]: radius (type: float) -Function 517: GenMeshPlane() (4 input parameters) +Function 518: GenMeshPlane() (4 input parameters) Name: GenMeshPlane Return type: Mesh Description: Generate plane mesh (with subdivisions) @@ -4358,42 +4363,42 @@ Function 517: GenMeshPlane() (4 input parameters) Param[2]: length (type: float) Param[3]: resX (type: int) Param[4]: resZ (type: int) -Function 518: GenMeshCube() (3 input parameters) +Function 519: GenMeshCube() (3 input parameters) Name: GenMeshCube Return type: Mesh Description: Generate cuboid mesh Param[1]: width (type: float) Param[2]: height (type: float) Param[3]: length (type: float) -Function 519: GenMeshSphere() (3 input parameters) +Function 520: GenMeshSphere() (3 input parameters) Name: GenMeshSphere Return type: Mesh Description: Generate sphere mesh (standard sphere) Param[1]: radius (type: float) Param[2]: rings (type: int) Param[3]: slices (type: int) -Function 520: GenMeshHemiSphere() (3 input parameters) +Function 521: GenMeshHemiSphere() (3 input parameters) Name: GenMeshHemiSphere Return type: Mesh Description: Generate half-sphere mesh (no bottom cap) Param[1]: radius (type: float) Param[2]: rings (type: int) Param[3]: slices (type: int) -Function 521: GenMeshCylinder() (3 input parameters) +Function 522: GenMeshCylinder() (3 input parameters) Name: GenMeshCylinder Return type: Mesh Description: Generate cylinder mesh Param[1]: radius (type: float) Param[2]: height (type: float) Param[3]: slices (type: int) -Function 522: GenMeshCone() (3 input parameters) +Function 523: GenMeshCone() (3 input parameters) Name: GenMeshCone Return type: Mesh Description: Generate cone/pyramid mesh Param[1]: radius (type: float) Param[2]: height (type: float) Param[3]: slices (type: int) -Function 523: GenMeshTorus() (4 input parameters) +Function 524: GenMeshTorus() (4 input parameters) Name: GenMeshTorus Return type: Mesh Description: Generate torus mesh @@ -4401,7 +4406,7 @@ Function 523: GenMeshTorus() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 524: GenMeshKnot() (4 input parameters) +Function 525: GenMeshKnot() (4 input parameters) Name: GenMeshKnot Return type: Mesh Description: Generate trefoil knot mesh @@ -4409,67 +4414,67 @@ Function 524: GenMeshKnot() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 525: GenMeshHeightmap() (2 input parameters) +Function 526: GenMeshHeightmap() (2 input parameters) Name: GenMeshHeightmap Return type: Mesh Description: Generate heightmap mesh from image data Param[1]: heightmap (type: Image) Param[2]: size (type: Vector3) -Function 526: GenMeshCubicmap() (2 input parameters) +Function 527: GenMeshCubicmap() (2 input parameters) Name: GenMeshCubicmap Return type: Mesh Description: Generate cubes-based map mesh from image data Param[1]: cubicmap (type: Image) Param[2]: cubeSize (type: Vector3) -Function 527: LoadMaterials() (2 input parameters) +Function 528: LoadMaterials() (2 input parameters) Name: LoadMaterials Return type: Material * Description: Load materials from model file Param[1]: fileName (type: const char *) Param[2]: materialCount (type: int *) -Function 528: LoadMaterialDefault() (0 input parameters) +Function 529: LoadMaterialDefault() (0 input parameters) Name: LoadMaterialDefault Return type: Material Description: Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) No input parameters -Function 529: IsMaterialValid() (1 input parameters) +Function 530: IsMaterialValid() (1 input parameters) Name: IsMaterialValid Return type: bool Description: Check if material is valid (shader assigned, map textures loaded in GPU) Param[1]: material (type: Material) -Function 530: UnloadMaterial() (1 input parameters) +Function 531: UnloadMaterial() (1 input parameters) Name: UnloadMaterial Return type: void Description: Unload material from GPU memory (VRAM) Param[1]: material (type: Material) -Function 531: SetMaterialTexture() (3 input parameters) +Function 532: SetMaterialTexture() (3 input parameters) Name: SetMaterialTexture Return type: void Description: Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...) Param[1]: material (type: Material *) Param[2]: mapType (type: int) Param[3]: texture (type: Texture2D) -Function 532: SetModelMeshMaterial() (3 input parameters) +Function 533: SetModelMeshMaterial() (3 input parameters) Name: SetModelMeshMaterial Return type: void Description: Set material for a mesh Param[1]: model (type: Model *) Param[2]: meshId (type: int) Param[3]: materialId (type: int) -Function 533: LoadModelAnimations() (2 input parameters) +Function 534: LoadModelAnimations() (2 input parameters) Name: LoadModelAnimations Return type: ModelAnimation * Description: Load model animations from file Param[1]: fileName (type: const char *) Param[2]: animCount (type: int *) -Function 534: UpdateModelAnimation() (3 input parameters) +Function 535: UpdateModelAnimation() (3 input parameters) Name: UpdateModelAnimation Return type: void Description: Update model animation pose (vertex buffers and bone matrices) Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) Param[3]: frame (type: float) -Function 535: UpdateModelAnimationEx() (6 input parameters) +Function 536: UpdateModelAnimationEx() (6 input parameters) Name: UpdateModelAnimationEx Return type: void Description: Update model animation pose, blending two animations @@ -4479,19 +4484,19 @@ Function 535: UpdateModelAnimationEx() (6 input parameters) Param[4]: animB (type: ModelAnimation) Param[5]: frameB (type: float) Param[6]: blend (type: float) -Function 536: UnloadModelAnimations() (2 input parameters) +Function 537: UnloadModelAnimations() (2 input parameters) Name: UnloadModelAnimations Return type: void Description: Unload animation array data Param[1]: animations (type: ModelAnimation *) Param[2]: animCount (type: int) -Function 537: IsModelAnimationValid() (2 input parameters) +Function 538: IsModelAnimationValid() (2 input parameters) Name: IsModelAnimationValid Return type: bool Description: Check model animation skeleton match Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) -Function 538: CheckCollisionSpheres() (4 input parameters) +Function 539: CheckCollisionSpheres() (4 input parameters) Name: CheckCollisionSpheres Return type: bool Description: Check collision between two spheres @@ -4499,40 +4504,40 @@ Function 538: CheckCollisionSpheres() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector3) Param[4]: radius2 (type: float) -Function 539: CheckCollisionBoxes() (2 input parameters) +Function 540: CheckCollisionBoxes() (2 input parameters) Name: CheckCollisionBoxes Return type: bool Description: Check collision between two bounding boxes Param[1]: box1 (type: BoundingBox) Param[2]: box2 (type: BoundingBox) -Function 540: CheckCollisionBoxSphere() (3 input parameters) +Function 541: CheckCollisionBoxSphere() (3 input parameters) Name: CheckCollisionBoxSphere Return type: bool Description: Check collision between box and sphere Param[1]: box (type: BoundingBox) Param[2]: center (type: Vector3) Param[3]: radius (type: float) -Function 541: GetRayCollisionSphere() (3 input parameters) +Function 542: GetRayCollisionSphere() (3 input parameters) Name: GetRayCollisionSphere Return type: RayCollision Description: Get collision info between ray and sphere Param[1]: ray (type: Ray) Param[2]: center (type: Vector3) Param[3]: radius (type: float) -Function 542: GetRayCollisionBox() (2 input parameters) +Function 543: GetRayCollisionBox() (2 input parameters) Name: GetRayCollisionBox Return type: RayCollision Description: Get collision info between ray and box Param[1]: ray (type: Ray) Param[2]: box (type: BoundingBox) -Function 543: GetRayCollisionMesh() (3 input parameters) +Function 544: GetRayCollisionMesh() (3 input parameters) Name: GetRayCollisionMesh Return type: RayCollision Description: Get collision info between ray and mesh Param[1]: ray (type: Ray) Param[2]: mesh (type: Mesh) Param[3]: transform (type: Matrix) -Function 544: GetRayCollisionTriangle() (4 input parameters) +Function 545: GetRayCollisionTriangle() (4 input parameters) Name: GetRayCollisionTriangle Return type: RayCollision Description: Get collision info between ray and triangle @@ -4540,7 +4545,7 @@ Function 544: GetRayCollisionTriangle() (4 input parameters) Param[2]: p1 (type: Vector3) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) -Function 545: GetRayCollisionQuad() (5 input parameters) +Function 546: GetRayCollisionQuad() (5 input parameters) Name: GetRayCollisionQuad Return type: RayCollision Description: Get collision info between ray and quad @@ -4549,158 +4554,158 @@ Function 545: GetRayCollisionQuad() (5 input parameters) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) Param[5]: p4 (type: Vector3) -Function 546: InitAudioDevice() (0 input parameters) +Function 547: InitAudioDevice() (0 input parameters) Name: InitAudioDevice Return type: void Description: Initialize audio device and context No input parameters -Function 547: CloseAudioDevice() (0 input parameters) +Function 548: CloseAudioDevice() (0 input parameters) Name: CloseAudioDevice Return type: void Description: Close the audio device and context No input parameters -Function 548: IsAudioDeviceReady() (0 input parameters) +Function 549: IsAudioDeviceReady() (0 input parameters) Name: IsAudioDeviceReady Return type: bool Description: Check if audio device has been initialized successfully No input parameters -Function 549: SetMasterVolume() (1 input parameters) +Function 550: SetMasterVolume() (1 input parameters) Name: SetMasterVolume Return type: void Description: Set master volume (listener) Param[1]: volume (type: float) -Function 550: GetMasterVolume() (0 input parameters) +Function 551: GetMasterVolume() (0 input parameters) Name: GetMasterVolume Return type: float Description: Get master volume (listener) No input parameters -Function 551: LoadWave() (1 input parameters) +Function 552: LoadWave() (1 input parameters) Name: LoadWave Return type: Wave Description: Load wave data from file Param[1]: fileName (type: const char *) -Function 552: LoadWaveFromMemory() (3 input parameters) +Function 553: LoadWaveFromMemory() (3 input parameters) Name: LoadWaveFromMemory Return type: Wave Description: Load wave from memory buffer, fileType refers to extension: i.e. '.wav' Param[1]: fileType (type: const char *) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 553: IsWaveValid() (1 input parameters) +Function 554: IsWaveValid() (1 input parameters) Name: IsWaveValid Return type: bool Description: Check if wave data is valid (data loaded and parameters) Param[1]: wave (type: Wave) -Function 554: LoadSound() (1 input parameters) +Function 555: LoadSound() (1 input parameters) Name: LoadSound Return type: Sound Description: Load sound from file Param[1]: fileName (type: const char *) -Function 555: LoadSoundFromWave() (1 input parameters) +Function 556: LoadSoundFromWave() (1 input parameters) Name: LoadSoundFromWave Return type: Sound Description: Load sound from wave data Param[1]: wave (type: Wave) -Function 556: LoadSoundAlias() (1 input parameters) +Function 557: LoadSoundAlias() (1 input parameters) Name: LoadSoundAlias Return type: Sound Description: Load sound alias, new sound that shares the same sample data as the source sound, does not own the sound data Param[1]: source (type: Sound) -Function 557: IsSoundValid() (1 input parameters) +Function 558: IsSoundValid() (1 input parameters) Name: IsSoundValid Return type: bool Description: Check if sound is valid (data loaded and buffers initialized) Param[1]: sound (type: Sound) -Function 558: UpdateSound() (3 input parameters) +Function 559: UpdateSound() (3 input parameters) Name: UpdateSound Return type: void Description: Update sound buffer with new data (default data format: 32 bit float, stereo) Param[1]: sound (type: Sound) Param[2]: data (type: const void *) Param[3]: frameCount (type: int) -Function 559: UnloadWave() (1 input parameters) +Function 560: UnloadWave() (1 input parameters) Name: UnloadWave Return type: void Description: Unload wave data Param[1]: wave (type: Wave) -Function 560: UnloadSound() (1 input parameters) +Function 561: UnloadSound() (1 input parameters) Name: UnloadSound Return type: void Description: Unload sound Param[1]: sound (type: Sound) -Function 561: UnloadSoundAlias() (1 input parameters) +Function 562: UnloadSoundAlias() (1 input parameters) Name: UnloadSoundAlias Return type: void Description: Unload sound alias (does not deallocate sample data) Param[1]: alias (type: Sound) -Function 562: ExportWave() (2 input parameters) +Function 563: ExportWave() (2 input parameters) Name: ExportWave Return type: bool Description: Export wave data to file, returns true on success Param[1]: wave (type: Wave) Param[2]: fileName (type: const char *) -Function 563: ExportWaveAsCode() (2 input parameters) +Function 564: ExportWaveAsCode() (2 input parameters) Name: ExportWaveAsCode Return type: bool Description: Export wave sample data to code (.h), returns true on success Param[1]: wave (type: Wave) Param[2]: fileName (type: const char *) -Function 564: PlaySound() (1 input parameters) +Function 565: PlaySound() (1 input parameters) Name: PlaySound Return type: void Description: Play a sound Param[1]: sound (type: Sound) -Function 565: StopSound() (1 input parameters) +Function 566: StopSound() (1 input parameters) Name: StopSound Return type: void Description: Stop playing a sound Param[1]: sound (type: Sound) -Function 566: PauseSound() (1 input parameters) +Function 567: PauseSound() (1 input parameters) Name: PauseSound Return type: void Description: Pause a sound Param[1]: sound (type: Sound) -Function 567: ResumeSound() (1 input parameters) +Function 568: ResumeSound() (1 input parameters) Name: ResumeSound Return type: void Description: Resume a paused sound Param[1]: sound (type: Sound) -Function 568: IsSoundPlaying() (1 input parameters) +Function 569: IsSoundPlaying() (1 input parameters) Name: IsSoundPlaying Return type: bool Description: Check if sound is currently playing Param[1]: sound (type: Sound) -Function 569: SetSoundVolume() (2 input parameters) +Function 570: SetSoundVolume() (2 input parameters) Name: SetSoundVolume Return type: void Description: Set volume for a sound (1.0 is max level) Param[1]: sound (type: Sound) Param[2]: volume (type: float) -Function 570: SetSoundPitch() (2 input parameters) +Function 571: SetSoundPitch() (2 input parameters) Name: SetSoundPitch Return type: void Description: Set pitch for a sound (1.0 is base level) Param[1]: sound (type: Sound) Param[2]: pitch (type: float) -Function 571: SetSoundPan() (2 input parameters) +Function 572: SetSoundPan() (2 input parameters) Name: SetSoundPan Return type: void Description: Set pan for a sound (-1.0 left, 0.0 center, 1.0 right) Param[1]: sound (type: Sound) Param[2]: pan (type: float) -Function 572: WaveCopy() (1 input parameters) +Function 573: WaveCopy() (1 input parameters) Name: WaveCopy Return type: Wave Description: Copy a wave to a new wave Param[1]: wave (type: Wave) -Function 573: WaveCrop() (3 input parameters) +Function 574: WaveCrop() (3 input parameters) Name: WaveCrop Return type: void Description: Crop a wave to defined frames range Param[1]: wave (type: Wave *) Param[2]: initFrame (type: int) Param[3]: finalFrame (type: int) -Function 574: WaveFormat() (4 input parameters) +Function 575: WaveFormat() (4 input parameters) Name: WaveFormat Return type: void Description: Convert wave data to desired format @@ -4708,203 +4713,203 @@ Function 574: WaveFormat() (4 input parameters) Param[2]: sampleRate (type: int) Param[3]: sampleSize (type: int) Param[4]: channels (type: int) -Function 575: LoadWaveSamples() (1 input parameters) +Function 576: LoadWaveSamples() (1 input parameters) Name: LoadWaveSamples Return type: float * Description: Load samples data from wave as a 32bit float data array Param[1]: wave (type: Wave) -Function 576: UnloadWaveSamples() (1 input parameters) +Function 577: UnloadWaveSamples() (1 input parameters) Name: UnloadWaveSamples Return type: void Description: Unload samples data loaded with LoadWaveSamples() Param[1]: samples (type: float *) -Function 577: LoadMusicStream() (1 input parameters) +Function 578: LoadMusicStream() (1 input parameters) Name: LoadMusicStream Return type: Music Description: Load music stream from file Param[1]: fileName (type: const char *) -Function 578: LoadMusicStreamFromMemory() (3 input parameters) +Function 579: LoadMusicStreamFromMemory() (3 input parameters) Name: LoadMusicStreamFromMemory Return type: Music Description: Load music stream from data Param[1]: fileType (type: const char *) Param[2]: data (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 579: IsMusicValid() (1 input parameters) +Function 580: IsMusicValid() (1 input parameters) Name: IsMusicValid Return type: bool Description: Check if music stream is valid (context and buffers initialized) Param[1]: music (type: Music) -Function 580: UnloadMusicStream() (1 input parameters) +Function 581: UnloadMusicStream() (1 input parameters) Name: UnloadMusicStream Return type: void Description: Unload music stream Param[1]: music (type: Music) -Function 581: PlayMusicStream() (1 input parameters) +Function 582: PlayMusicStream() (1 input parameters) Name: PlayMusicStream Return type: void Description: Start music playing Param[1]: music (type: Music) -Function 582: IsMusicStreamPlaying() (1 input parameters) +Function 583: IsMusicStreamPlaying() (1 input parameters) Name: IsMusicStreamPlaying Return type: bool Description: Check if music is playing Param[1]: music (type: Music) -Function 583: UpdateMusicStream() (1 input parameters) +Function 584: UpdateMusicStream() (1 input parameters) Name: UpdateMusicStream Return type: void Description: Update buffers for music streaming Param[1]: music (type: Music) -Function 584: StopMusicStream() (1 input parameters) +Function 585: StopMusicStream() (1 input parameters) Name: StopMusicStream Return type: void Description: Stop music playing Param[1]: music (type: Music) -Function 585: PauseMusicStream() (1 input parameters) +Function 586: PauseMusicStream() (1 input parameters) Name: PauseMusicStream Return type: void Description: Pause music playing Param[1]: music (type: Music) -Function 586: ResumeMusicStream() (1 input parameters) +Function 587: ResumeMusicStream() (1 input parameters) Name: ResumeMusicStream Return type: void Description: Resume playing paused music Param[1]: music (type: Music) -Function 587: SeekMusicStream() (2 input parameters) +Function 588: SeekMusicStream() (2 input parameters) Name: SeekMusicStream Return type: void Description: Seek music to a position (in seconds) Param[1]: music (type: Music) Param[2]: position (type: float) -Function 588: SetMusicVolume() (2 input parameters) +Function 589: SetMusicVolume() (2 input parameters) Name: SetMusicVolume Return type: void Description: Set volume for music (1.0 is max level) Param[1]: music (type: Music) Param[2]: volume (type: float) -Function 589: SetMusicPitch() (2 input parameters) +Function 590: SetMusicPitch() (2 input parameters) Name: SetMusicPitch Return type: void Description: Set pitch for music (1.0 is base level) Param[1]: music (type: Music) Param[2]: pitch (type: float) -Function 590: SetMusicPan() (2 input parameters) +Function 591: SetMusicPan() (2 input parameters) Name: SetMusicPan Return type: void Description: Set pan for music (-1.0 left, 0.0 center, 1.0 right) Param[1]: music (type: Music) Param[2]: pan (type: float) -Function 591: GetMusicTimeLength() (1 input parameters) +Function 592: GetMusicTimeLength() (1 input parameters) Name: GetMusicTimeLength Return type: float Description: Get music time length (in seconds) Param[1]: music (type: Music) -Function 592: GetMusicTimePlayed() (1 input parameters) +Function 593: GetMusicTimePlayed() (1 input parameters) Name: GetMusicTimePlayed Return type: float Description: Get current music time played (in seconds) Param[1]: music (type: Music) -Function 593: LoadAudioStream() (3 input parameters) +Function 594: LoadAudioStream() (3 input parameters) Name: LoadAudioStream Return type: AudioStream Description: Load audio stream (to stream raw audio pcm data) Param[1]: sampleRate (type: unsigned int) Param[2]: sampleSize (type: unsigned int) Param[3]: channels (type: unsigned int) -Function 594: IsAudioStreamValid() (1 input parameters) +Function 595: IsAudioStreamValid() (1 input parameters) Name: IsAudioStreamValid Return type: bool Description: Check if an audio stream is valid (buffers initialized) Param[1]: stream (type: AudioStream) -Function 595: UnloadAudioStream() (1 input parameters) +Function 596: UnloadAudioStream() (1 input parameters) Name: UnloadAudioStream Return type: void Description: Unload audio stream and free memory Param[1]: stream (type: AudioStream) -Function 596: UpdateAudioStream() (3 input parameters) +Function 597: UpdateAudioStream() (3 input parameters) Name: UpdateAudioStream Return type: void Description: Update audio stream buffers with data Param[1]: stream (type: AudioStream) Param[2]: data (type: const void *) Param[3]: frameCount (type: int) -Function 597: IsAudioStreamProcessed() (1 input parameters) +Function 598: IsAudioStreamProcessed() (1 input parameters) Name: IsAudioStreamProcessed Return type: bool Description: Check if any audio stream buffers requires refill Param[1]: stream (type: AudioStream) -Function 598: PlayAudioStream() (1 input parameters) +Function 599: PlayAudioStream() (1 input parameters) Name: PlayAudioStream Return type: void Description: Play audio stream Param[1]: stream (type: AudioStream) -Function 599: PauseAudioStream() (1 input parameters) +Function 600: PauseAudioStream() (1 input parameters) Name: PauseAudioStream Return type: void Description: Pause audio stream Param[1]: stream (type: AudioStream) -Function 600: ResumeAudioStream() (1 input parameters) +Function 601: ResumeAudioStream() (1 input parameters) Name: ResumeAudioStream Return type: void Description: Resume audio stream Param[1]: stream (type: AudioStream) -Function 601: IsAudioStreamPlaying() (1 input parameters) +Function 602: IsAudioStreamPlaying() (1 input parameters) Name: IsAudioStreamPlaying Return type: bool Description: Check if audio stream is playing Param[1]: stream (type: AudioStream) -Function 602: StopAudioStream() (1 input parameters) +Function 603: StopAudioStream() (1 input parameters) Name: StopAudioStream Return type: void Description: Stop audio stream Param[1]: stream (type: AudioStream) -Function 603: SetAudioStreamVolume() (2 input parameters) +Function 604: SetAudioStreamVolume() (2 input parameters) Name: SetAudioStreamVolume Return type: void Description: Set volume for audio stream (1.0 is max level) Param[1]: stream (type: AudioStream) Param[2]: volume (type: float) -Function 604: SetAudioStreamPitch() (2 input parameters) +Function 605: SetAudioStreamPitch() (2 input parameters) Name: SetAudioStreamPitch Return type: void Description: Set pitch for audio stream (1.0 is base level) Param[1]: stream (type: AudioStream) Param[2]: pitch (type: float) -Function 605: SetAudioStreamPan() (2 input parameters) +Function 606: SetAudioStreamPan() (2 input parameters) Name: SetAudioStreamPan Return type: void Description: Set pan for audio stream (-1.0 left, 0.0 center, 1.0 right) Param[1]: stream (type: AudioStream) Param[2]: pan (type: float) -Function 606: SetAudioStreamBufferSizeDefault() (1 input parameters) +Function 607: SetAudioStreamBufferSizeDefault() (1 input parameters) Name: SetAudioStreamBufferSizeDefault Return type: void Description: Default size for new audio streams Param[1]: size (type: int) -Function 607: SetAudioStreamCallback() (2 input parameters) +Function 608: SetAudioStreamCallback() (2 input parameters) Name: SetAudioStreamCallback Return type: void Description: Audio thread callback to request new data Param[1]: stream (type: AudioStream) Param[2]: callback (type: AudioCallback) -Function 608: AttachAudioStreamProcessor() (2 input parameters) +Function 609: AttachAudioStreamProcessor() (2 input parameters) Name: AttachAudioStreamProcessor Return type: void Description: Attach audio stream processor to stream, receives frames x 2 samples as 'float' (stereo) Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 609: DetachAudioStreamProcessor() (2 input parameters) +Function 610: DetachAudioStreamProcessor() (2 input parameters) Name: DetachAudioStreamProcessor Return type: void Description: Detach audio stream processor from stream Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 610: AttachAudioMixedProcessor() (1 input parameters) +Function 611: AttachAudioMixedProcessor() (1 input parameters) Name: AttachAudioMixedProcessor Return type: void Description: Attach audio stream processor to the entire audio pipeline, receives frames x 2 samples as 'float' (stereo) Param[1]: processor (type: AudioCallback) -Function 611: DetachAudioMixedProcessor() (1 input parameters) +Function 612: DetachAudioMixedProcessor() (1 input parameters) Name: DetachAudioMixedProcessor Return type: void Description: Detach audio stream processor from the entire audio pipeline diff --git a/tools/rlparser/output/raylib_api.xml b/tools/rlparser/output/raylib_api.xml index 6dd00a610..b86c28b7a 100644 --- a/tools/rlparser/output/raylib_api.xml +++ b/tools/rlparser/output/raylib_api.xml @@ -681,7 +681,7 @@ - + @@ -1115,7 +1115,10 @@ - + + + + From 5e374218eec7f137fb8f28c75fd97a639628efa1 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 2 Jul 2026 18:58:01 +0200 Subject: [PATCH 27/94] REVIEWED: Set mouse position to (0,0) when mouse leaves window area #5945 --- src/platforms/rcore_desktop_glfw.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index 55b92ac79..64596b376 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -151,7 +151,7 @@ static void CharCallback(GLFWwindow *window, unsigned int codepoint); static void MouseButtonCallback(GLFWwindow *window, int button, int action, int mods); // GLFW3 Mouse Button Callback, runs on mouse button pressed static void MouseCursorPosCallback(GLFWwindow *window, double x, double y); // GLFW3 Cursor Position Callback, runs on mouse move static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffset); // GLFW3 Scrolling Callback, runs on mouse wheel -static void CursorEnterCallback(GLFWwindow *window, int enter); // GLFW3 Cursor Enter Callback, cursor enters client area +static void CursorEnterCallback(GLFWwindow *window, int entered); // GLFW3 Cursor Enter Callback, cursor enters client area static void JoystickCallback(int jid, int event); // GLFW3 Joystick Connected/Disconnected Callback // Memory allocator wrappers [used by glfwInitAllocator()] @@ -2167,10 +2167,18 @@ static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffs } // GLFW3: Cursor ennter callback, when cursor enters the window -static void CursorEnterCallback(GLFWwindow *window, int enter) +static void CursorEnterCallback(GLFWwindow *window, int entered) { - if (enter) CORE.Input.Mouse.cursorOnScreen = true; - else CORE.Input.Mouse.cursorOnScreen = false; + if (entered) + { + // NOTE: Mouse position updated by MouseCursorPosCallback() + CORE.Input.Mouse.cursorOnScreen = true; + } + else + { + CORE.Input.Mouse.cursorOnScreen = false; + CORE.Input.Mouse.currentPosition = (Vector2){ 0 }; + } } // GLFW3: Joystick connected/disconnected callback From 350124a45b333dc173ad895915d4db9c4ef74566 Mon Sep 17 00:00:00 2001 From: 0xFishbyte <126165205+0xFishbyte@users.noreply.github.com> Date: Fri, 3 Jul 2026 02:00:51 +0300 Subject: [PATCH 28/94] [rcore] Fix SDL3 backend using wrong joystick functions (#5948) * [rcore] Fix gamepad code using outdated functions * [rcore] Remove printing available joysticks --- src/platforms/rcore_desktop_sdl.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index c96820475..8fd67b6d0 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -2164,11 +2164,20 @@ int InitPlatform(void) platform.gamepadId[i] = -1; // Set all gamepad initial instance ids as invalid to not conflict with instance id zero } +#if defined(USING_VERSION_SDL3) + int numJoysticks; + SDL_JoystickID *joysticks = SDL_GetJoysticks(&numJoysticks); +#else int numJoysticks = SDL_NumJoysticks(); +#endif for (int i = 0; (i < numJoysticks) && (i < MAX_GAMEPADS); i++) { +#if defined(USING_VERSION_SDL3) + platform.gamepad[i] = SDL_OpenGamepad(joysticks[i]); +#else platform.gamepad[i] = SDL_GameControllerOpen(i); +#endif platform.gamepadId[i] = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(platform.gamepad[i])); if (platform.gamepad[i]) @@ -2177,7 +2186,12 @@ int InitPlatform(void) CORE.Input.Gamepad.axisCount[i] = SDL_JoystickNumAxes(SDL_GameControllerGetJoystick(platform.gamepad[i])); CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f; CORE.Input.Gamepad.axisState[i][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f; - strncpy(CORE.Input.Gamepad.name[i], SDL_GameControllerNameForIndex(i), MAX_GAMEPAD_NAME_LENGTH - 1); +#if defined(USING_VERSION_SDL3) + const char *joystickName = SDL_GetJoystickNameForID(joysticks[i]); +#else + const char *joystickName = SDL_GameControllerNameForIndex(i); +#endif + strncpy(CORE.Input.Gamepad.name[i], joystickName, MAX_GAMEPAD_NAME_LENGTH - 1); CORE.Input.Gamepad.name[i][MAX_GAMEPAD_NAME_LENGTH - 1] = '\0'; } else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError()); From bb96b920d34eed642a5076d21684aeb1f36ef044 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 3 Jul 2026 11:31:45 +0200 Subject: [PATCH 29/94] Update rtextures.c --- src/rtextures.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rtextures.c b/src/rtextures.c index 6092cb57c..41ee1ffd1 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -3927,7 +3927,7 @@ void ImageDrawRectanglePro(Image *dst, Rectangle rec, Vector2 origin, float rota // Draw rectangle lines within an image void ImageDrawRectangleLines(Image *dst, int posX, int posY, int width, int height, Color color) { - Rectangle rec = { posX, posY, width, height }; + Rectangle rec = { (float)posX, (float)posY, (float)width, (float)height }; ImageDrawRectangleLinesEx(dst, rec, 1, color); } @@ -4019,8 +4019,8 @@ void ImageDrawCircleGradient(Image *dst, Vector2 center, float radius, Color inn // Draw an image within an image void ImageDrawImage(Image *dst, Image src, int posX, int posY, Color tint) { - Rectangle srcRec = { 0, 0, src.width, src.height }; - Rectangle dstRec = { posX, posY, srcRec.width, srcRec.height }; + Rectangle srcRec = { 0.0f, 0.0f, (float)src.width, (float)src.height }; + Rectangle dstRec = { (float)posX, (float)posY, srcRec.width, srcRec.height }; ImageDrawImagePro(dst, src, srcRec, dstRec, (Vector2){ 0 }, 0.0f, tint); } From 1911a2827bad6e7cfec35e7c7af32dee60386636 Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 3 Jul 2026 23:09:19 +0200 Subject: [PATCH 30/94] REVIEWED: GitHub Actuions update to latest actions --- .github/workflows/analyze_codeql.yml | 4 ++-- .github/workflows/build_android.yml | 6 +++--- .github/workflows/build_cmake.yml | 4 ++-- .github/workflows/build_examples_linux.yml | 2 +- .github/workflows/build_examples_windows.yml | 2 +- .github/workflows/build_linux.yml | 6 +++--- .github/workflows/build_macos.yml | 6 +++--- .github/workflows/build_webassembly.yml | 4 ++-- .github/workflows/build_windows.yml | 8 ++++---- .github/workflows/parse_api.yml | 2 +- .github/workflows/update_examples.yml | 2 +- 11 files changed, 23 insertions(+), 23 deletions(-) diff --git a/.github/workflows/analyze_codeql.yml b/.github/workflows/analyze_codeql.yml index 5fd169dd0..6598aa063 100644 --- a/.github/workflows/analyze_codeql.yml +++ b/.github/workflows/analyze_codeql.yml @@ -44,7 +44,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@master with: submodules: recursive @@ -128,7 +128,7 @@ jobs: - name: Upload CodeQL results as an artifact if: success() || failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: codeql-results path: ${{ steps.step1.outputs.sarif-output }} diff --git a/.github/workflows/build_android.yml b/.github/workflows/build_android.yml index c87807847..b4efab67c 100644 --- a/.github/workflows/build_android.yml +++ b/.github/workflows/build_android.yml @@ -21,7 +21,7 @@ permissions: jobs: build: permissions: - contents: write # for actions/upload-release-asset to upload release asset + contents: write # Required for actions/upload-release-asset to upload release asset runs-on: windows-latest strategy: fail-fast: false @@ -82,7 +82,7 @@ jobs: tar -czvf ${{ env.RELEASE_NAME }}.tar.gz ${{ env.RELEASE_NAME }} - name: Upload Artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: ${{ env.RELEASE_NAME }} path: | @@ -90,7 +90,7 @@ jobs: !./build/${{ env.RELEASE_NAME }}.tar.gz - name: Upload Artifact to Release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v3 with: files: ./build/${{ env.RELEASE_NAME }}.tar.gz env: diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml index 0158fb510..da1993026 100644 --- a/.github/workflows/build_cmake.yml +++ b/.github/workflows/build_cmake.yml @@ -36,7 +36,7 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@master - name: Create Build Environment # Some projects don't allow in-source building, so create a separate build directory @@ -75,7 +75,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@master - name: Create Build Environment # Some projects don't allow in-source building, so create a separate build directory diff --git a/.github/workflows/build_examples_linux.yml b/.github/workflows/build_examples_linux.yml index c293efd1d..ca15acd81 100644 --- a/.github/workflows/build_examples_linux.yml +++ b/.github/workflows/build_examples_linux.yml @@ -22,7 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@master - name: Setup Environment run: | diff --git a/.github/workflows/build_examples_windows.yml b/.github/workflows/build_examples_windows.yml index 4cc2e84b9..186242c24 100644 --- a/.github/workflows/build_examples_windows.yml +++ b/.github/workflows/build_examples_windows.yml @@ -22,7 +22,7 @@ jobs: runs-on: windows-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@master - name: Add MSBuild to PATH uses: microsoft/setup-msbuild@v1 diff --git a/.github/workflows/build_linux.yml b/.github/workflows/build_linux.yml index 0fc32d374..fa1c0b82c 100644 --- a/.github/workflows/build_linux.yml +++ b/.github/workflows/build_linux.yml @@ -21,7 +21,7 @@ permissions: jobs: build: permissions: - contents: write # for actions/upload-release-asset to upload release asset + contents: write # Required for actions/upload-release-asset to upload release asset strategy: fail-fast: false max-parallel: 1 @@ -112,7 +112,7 @@ jobs: tar -czvf ${{ env.RELEASE_NAME }}.tar.gz ${{ env.RELEASE_NAME }} - name: Upload Artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: ${{ env.RELEASE_NAME }} path: | @@ -120,7 +120,7 @@ jobs: !./build/${{ env.RELEASE_NAME }}.tar.gz - name: Upload Artifact to Release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v3 with: files: ./build/${{ env.RELEASE_NAME }}.tar.gz env: diff --git a/.github/workflows/build_macos.yml b/.github/workflows/build_macos.yml index 08ea0188a..9da31412e 100644 --- a/.github/workflows/build_macos.yml +++ b/.github/workflows/build_macos.yml @@ -21,7 +21,7 @@ permissions: jobs: build: permissions: - contents: write # for actions/upload-release-asset to upload release asset + contents: write # Required for actions/upload-release-asset to upload release asset runs-on: macos-latest env: @@ -99,7 +99,7 @@ jobs: tar -czvf ${{ env.RELEASE_NAME }}.tar.gz ${{ env.RELEASE_NAME }} - name: Upload Artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: ${{ env.RELEASE_NAME }} path: | @@ -107,7 +107,7 @@ jobs: !./build/${{ env.RELEASE_NAME }}.tar.gz - name: Upload Artifact to Release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v3 with: files: ./build/${{ env.RELEASE_NAME }}.tar.gz env: diff --git a/.github/workflows/build_webassembly.yml b/.github/workflows/build_webassembly.yml index 1e4066c26..edc8a9a10 100644 --- a/.github/workflows/build_webassembly.yml +++ b/.github/workflows/build_webassembly.yml @@ -69,7 +69,7 @@ jobs: shell: cmd - name: Upload Artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: ${{ env.RELEASE_NAME }} path: | @@ -77,7 +77,7 @@ jobs: !./build/${{ env.RELEASE_NAME }}.zip - name: Upload Artifact to Release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v3 with: files: ./build/${{ env.RELEASE_NAME }}.zip env: diff --git a/.github/workflows/build_windows.yml b/.github/workflows/build_windows.yml index 988428403..10b7ca91b 100644 --- a/.github/workflows/build_windows.yml +++ b/.github/workflows/build_windows.yml @@ -21,7 +21,7 @@ permissions: jobs: build: permissions: - contents: write # for actions/upload-release-asset to upload release asset + contents: write # Required for actions/upload-release-asset to upload release asset runs-on: windows-latest strategy: fail-fast: false @@ -81,7 +81,7 @@ jobs: # Setup MSBuild.exe path if required - name: Setup MSBuild - uses: microsoft/setup-msbuild@v2 + uses: microsoft/setup-msbuild@v3 if: matrix.compiler == 'msvc16' - name: Build Library (MinGW-w64 32bit) @@ -140,7 +140,7 @@ jobs: shell: cmd - name: Upload Artifacts - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: ${{ env.RELEASE_NAME }} path: | @@ -148,7 +148,7 @@ jobs: !./build/${{ env.RELEASE_NAME }}.zip - name: Upload Artifact to Release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v3 with: files: ./build/${{ env.RELEASE_NAME }}.zip env: diff --git a/.github/workflows/parse_api.yml b/.github/workflows/parse_api.yml index e25cde18b..36f7fb5db 100644 --- a/.github/workflows/parse_api.yml +++ b/.github/workflows/parse_api.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@master - name: Update parse files working-directory: tools/rlparser diff --git a/.github/workflows/update_examples.yml b/.github/workflows/update_examples.yml index fe8e4c48f..83a556e5b 100644 --- a/.github/workflows/update_examples.yml +++ b/.github/workflows/update_examples.yml @@ -15,7 +15,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@master - name: Setup emsdk uses: mymindstorm/setup-emsdk@v14 From 65abee1cbade6bf7edf55da6eb1eed6980aa754b Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 4 Jul 2026 12:25:06 +0200 Subject: [PATCH 31/94] Updated GA setup-emsdk action --- .github/workflows/build_webassembly.yml | 2 +- .github/workflows/update_examples.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_webassembly.yml b/.github/workflows/build_webassembly.yml index edc8a9a10..ae4b37087 100644 --- a/.github/workflows/build_webassembly.yml +++ b/.github/workflows/build_webassembly.yml @@ -27,7 +27,7 @@ jobs: uses: actions/checkout@master - name: Setup emsdk - uses: mymindstorm/setup-emsdk@v14 + uses: emscripten-core/setup-emsdk@v15 with: version: 5.0.3 actions-cache-folder: 'emsdk-cache' diff --git a/.github/workflows/update_examples.yml b/.github/workflows/update_examples.yml index 83a556e5b..1d1edc524 100644 --- a/.github/workflows/update_examples.yml +++ b/.github/workflows/update_examples.yml @@ -18,7 +18,7 @@ jobs: uses: actions/checkout@master - name: Setup emsdk - uses: mymindstorm/setup-emsdk@v14 + uses: emscripten-core/setup-emsdk@v15 with: version: 'latest' actions-cache-folder: 'emsdk-cache' From 2e03c9c266ece3827aa5dadb6ba8f78ac912be5b Mon Sep 17 00:00:00 2001 From: Laurentino <81370009+lauchimoon@users.noreply.github.com> Date: Mon, 6 Jul 2026 13:33:01 -0300 Subject: [PATCH 32/94] Change boneCount field type from int to unsigned int (#5955) --- src/raylib.h | 4 ++-- src/rmodels.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index 35f3c40a9..f0e67f535 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -409,7 +409,7 @@ typedef struct BoneInfo { // Skeleton, animation bones hierarchy typedef struct ModelSkeleton { - int boneCount; // Number of bones + unsigned int boneCount; // Number of bones BoneInfo *bones; // Bones information (skeleton) ModelAnimPose bindPose; // Bones base transformation (Transform[]) } ModelSkeleton; @@ -436,7 +436,7 @@ typedef struct Model { typedef struct ModelAnimation { char name[32]; // Animation name - int boneCount; // Number of bones (per pose) + unsigned int boneCount; // Number of bones (per pose) int keyframeCount; // Number of animation key frames ModelAnimPose *keyframePoses; // Animation sequence keyframe poses [keyframe][pose] } ModelAnimation; diff --git a/src/rmodels.c b/src/rmodels.c index 28fb3c9ec..08692028c 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -5369,9 +5369,9 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat } // Load bone info from GLTF skin data -static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, int *boneCount) +static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, unsigned int *boneCount) { - *boneCount = (int)skin.joints_count; + *boneCount = skin.joints_count; BoneInfo *bones = (BoneInfo *)RL_CALLOC(skin.joints_count, sizeof(BoneInfo)); for (unsigned int i = 0; i < skin.joints_count; i++) From 088177b269a8eb51d55cd80235d8836b277c97a1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 6 Jul 2026 16:33:13 +0000 Subject: [PATCH 33/94] rlparser: update raylib_api.* by CI --- tools/rlparser/output/raylib_api.json | 4 ++-- tools/rlparser/output/raylib_api.lua | 4 ++-- tools/rlparser/output/raylib_api.sexpr | 4 ++-- tools/rlparser/output/raylib_api.txt | 4 ++-- tools/rlparser/output/raylib_api.xml | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/rlparser/output/raylib_api.json b/tools/rlparser/output/raylib_api.json index de1ebc884..2e6916737 100644 --- a/tools/rlparser/output/raylib_api.json +++ b/tools/rlparser/output/raylib_api.json @@ -968,7 +968,7 @@ "description": "Skeleton, animation bones hierarchy", "fields": [ { - "type": "int", + "type": "unsigned int", "name": "boneCount", "description": "Number of bones" }, @@ -1045,7 +1045,7 @@ "description": "Animation name" }, { - "type": "int", + "type": "unsigned int", "name": "boneCount", "description": "Number of bones (per pose)" }, diff --git a/tools/rlparser/output/raylib_api.lua b/tools/rlparser/output/raylib_api.lua index 98308682d..574cfbf2d 100644 --- a/tools/rlparser/output/raylib_api.lua +++ b/tools/rlparser/output/raylib_api.lua @@ -968,7 +968,7 @@ return { description = "Skeleton, animation bones hierarchy", fields = { { - type = "int", + type = "unsigned int", name = "boneCount", description = "Number of bones" }, @@ -1045,7 +1045,7 @@ return { description = "Animation name" }, { - type = "int", + type = "unsigned int", name = "boneCount", description = "Number of bones (per pose)" }, diff --git a/tools/rlparser/output/raylib_api.sexpr b/tools/rlparser/output/raylib_api.sexpr index e4dee877c..e57c282a3 100644 --- a/tools/rlparser/output/raylib_api.sexpr +++ b/tools/rlparser/output/raylib_api.sexpr @@ -611,7 +611,7 @@ ((name "ModelSkeleton") (description "Skeleton, animation bones hierarchy") (fields - ((type "int") + ((type "unsigned int") (name "boneCount") (description "Number of bones")) ((type "BoneInfo *") @@ -658,7 +658,7 @@ ((type "char[32]") (name "name") (description "Animation name")) - ((type "int") + ((type "unsigned int") (name "boneCount") (description "Number of bones (per pose)")) ((type "int") diff --git a/tools/rlparser/output/raylib_api.txt b/tools/rlparser/output/raylib_api.txt index 77a1dba1f..d0d60463c 100644 --- a/tools/rlparser/output/raylib_api.txt +++ b/tools/rlparser/output/raylib_api.txt @@ -448,7 +448,7 @@ Struct 20: BoneInfo (2 fields) Struct 21: ModelSkeleton (3 fields) Name: ModelSkeleton Description: Skeleton, animation bones hierarchy - Field[1]: int boneCount // Number of bones + Field[1]: unsigned int boneCount // Number of bones Field[2]: BoneInfo * bones // Bones information (skeleton) Field[3]: ModelAnimPose bindPose // Bones base transformation (Transform[]) Struct 22: Model (9 fields) @@ -467,7 +467,7 @@ Struct 23: ModelAnimation (4 fields) Name: ModelAnimation Description: ModelAnimation, contains a full animation sequence Field[1]: char[32] name // Animation name - Field[2]: int boneCount // Number of bones (per pose) + Field[2]: unsigned int boneCount // Number of bones (per pose) Field[3]: int keyframeCount // Number of animation key frames Field[4]: ModelAnimPose * keyframePoses // Animation sequence keyframe poses [keyframe][pose] Struct 24: Ray (2 fields) diff --git a/tools/rlparser/output/raylib_api.xml b/tools/rlparser/output/raylib_api.xml index b86c28b7a..77eb75c73 100644 --- a/tools/rlparser/output/raylib_api.xml +++ b/tools/rlparser/output/raylib_api.xml @@ -201,7 +201,7 @@ - + @@ -218,7 +218,7 @@ - + From 3d640698d83ee1f1bb32981c8018019b63330bca Mon Sep 17 00:00:00 2001 From: Timothy Fiss Date: Mon, 6 Jul 2026 10:35:02 -0600 Subject: [PATCH 34/94] fix UB in ComputeSHA-1 (#5957) --- src/rcore.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index d1163a515..0401817bf 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -3379,10 +3379,10 @@ unsigned int *ComputeSHA1(const unsigned char *data, int dataSize) unsigned int w[80] = { 0 }; for (int i = 0; i < 16; i++) { - w[i] = (msg[offset + (i*4) + 0] << 24) | - (msg[offset + (i*4) + 1] << 16) | - (msg[offset + (i*4) + 2] << 8) | - (msg[offset + (i*4) + 3]); + w[i] = ((unsigned int)msg[offset + (i*4) + 0] << 24) | + ((unsigned int)msg[offset + (i*4) + 1] << 16) | + ((unsigned int)msg[offset + (i*4) + 2] << 8) | + ((unsigned int)msg[offset + (i*4) + 3]); } // Message schedule: extend the sixteen 32-bit words into eighty 32-bit words: From 5992929e562ebb4ec89a8d065de089b6d96d2c42 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 6 Jul 2026 19:13:44 +0200 Subject: [PATCH 35/94] REVIEWED: Security: `strncpy()` replaced by `snprintf()` --- src/platforms/rcore_desktop_glfw.c | 6 +- src/platforms/rcore_desktop_rgfw.c | 108 ++++++++++++++------------- src/platforms/rcore_desktop_sdl.c | 14 ++-- src/platforms/rcore_web.c | 2 +- src/platforms/rcore_web_emscripten.c | 2 +- src/raudio.c | 4 +- src/rcore.c | 25 +++---- src/rlgl.h | 2 +- src/rmodels.c | 18 ++--- src/rtext.c | 22 +++--- src/rtextures.c | 2 +- tools/rexm/rexm.c | 8 +- 12 files changed, 107 insertions(+), 106 deletions(-) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index 64596b376..b0bdf70f3 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -1829,7 +1829,7 @@ int InitPlatform(void) { CORE.Input.Gamepad.ready[i] = true; CORE.Input.Gamepad.axisCount[i] = GLFW_GAMEPAD_AXIS_LAST + 1; - strncpy(CORE.Input.Gamepad.name[i], glfwGetJoystickName(i), MAX_GAMEPAD_NAME_LENGTH - 1); + snprintf(CORE.Input.Gamepad.name[i], MAX_GAMEPAD_NAME_LENGTH, "%s", glfwGetJoystickName(i)); } } //---------------------------------------------------------------------------- @@ -2044,7 +2044,7 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) { CORE.Window.dropFilepaths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); - strncpy(CORE.Window.dropFilepaths[i], paths[i], MAX_FILEPATH_LENGTH - 1); + snprintf(CORE.Window.dropFilepaths[i], MAX_FILEPATH_LENGTH, "%s", paths[i]); } } } @@ -2191,7 +2191,7 @@ static void JoystickCallback(int jid, int event) // WARNING: If glfwGetJoystickName() is longer than MAX_GAMEPAD_NAME_LENGTH, // only copy up to (MAX_GAMEPAD_NAME_LENGTH -1) to destination string memset(CORE.Input.Gamepad.name[jid], 0, MAX_GAMEPAD_NAME_LENGTH); - strncpy(CORE.Input.Gamepad.name[jid], glfwGetJoystickName(jid), MAX_GAMEPAD_NAME_LENGTH - 1); + snprintf(CORE.Input.Gamepad.name[jid], MAX_GAMEPAD_NAME_LENGTH, "%s", glfwGetJoystickName(jid)); } else if (event == GLFW_DISCONNECTED) { diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index 211917359..2e973108b 100644 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -486,14 +486,14 @@ static void RGFW_cb_dropfunc(const RGFW_event *e) CORE.Window.dropFilepaths = (char **)RL_CALLOC(1024, sizeof(char *)); CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); - strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], e->drop.value->data); + snprintf(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], MAX_FILEPATH_LENGTH, "%s", e->drop.value->data); CORE.Window.dropFileCount++; } else if (CORE.Window.dropFileCount < 1024) { CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); - strcpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], e->drop.value->data); + snprintf(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], MAX_FILEPATH_LENGTH, "%s", e->drop.value->data); CORE.Window.dropFileCount++; } @@ -1609,74 +1609,76 @@ void PollInputEvents(void) //----------------------------------------------------------------------------- mg_event gamepad_event; - while (mg_gamepads_check_event(&platform.minigamepad, &gamepad_event)) { + while (mg_gamepads_check_event(&platform.minigamepad, &gamepad_event)) + { int gamepadIndex = gamepad_event.gamepad->index; - switch (gamepad_event.type) { + + switch (gamepad_event.type) + { case MG_EVENT_BUTTON_PRESS: + { + int button = mg_buttonConvertTable[gamepad_event.button]; + if (button >= 0) { - int button = mg_buttonConvertTable[gamepad_event.button]; - if (button >= 0) - { - CORE.Input.Gamepad.currentButtonState[gamepadIndex][button] = 1; - CORE.Input.Gamepad.lastButtonPressed = button; - } - } break; + CORE.Input.Gamepad.currentButtonState[gamepadIndex][button] = 1; + CORE.Input.Gamepad.lastButtonPressed = button; + } + } break; case MG_EVENT_BUTTON_RELEASE: + { + int button = mg_buttonConvertTable[gamepad_event.button]; + if (button >= 0) { - int button = mg_buttonConvertTable[gamepad_event.button]; - if (button >= 0) - { - CORE.Input.Gamepad.currentButtonState[gamepadIndex][button] = 0; - if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0; - } - } break; + CORE.Input.Gamepad.currentButtonState[gamepadIndex][button] = 0; + if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0; + } + } break; case MG_EVENT_AXIS_MOVE: - { - int axis = mg_axisConvertTable[gamepad_event.axis]; + { + int axis = mg_axisConvertTable[gamepad_event.axis]; - switch (axis) { - case GAMEPAD_AXIS_LEFT_X: - case GAMEPAD_AXIS_LEFT_Y: - case GAMEPAD_AXIS_RIGHT_X: - case GAMEPAD_AXIS_RIGHT_Y: - CORE.Input.Gamepad.axisState[gamepadIndex][axis] = platform.minigamepad.gamepads[gamepadIndex].axes[gamepad_event.axis].value; - break; - case GAMEPAD_AXIS_LEFT_TRIGGER: - case GAMEPAD_AXIS_RIGHT_TRIGGER: - CORE.Input.Gamepad.axisState[gamepadIndex][axis] = platform.minigamepad.gamepads[gamepadIndex].axes[gamepad_event.axis].value; + switch (axis) { + case GAMEPAD_AXIS_LEFT_X: + case GAMEPAD_AXIS_LEFT_Y: + case GAMEPAD_AXIS_RIGHT_X: + case GAMEPAD_AXIS_RIGHT_Y: + { + CORE.Input.Gamepad.axisState[gamepadIndex][axis] = platform.minigamepad.gamepads[gamepadIndex].axes[gamepad_event.axis].value; + } break; + case GAMEPAD_AXIS_LEFT_TRIGGER: + case GAMEPAD_AXIS_RIGHT_TRIGGER: + { + CORE.Input.Gamepad.axisState[gamepadIndex][axis] = platform.minigamepad.gamepads[gamepadIndex].axes[gamepad_event.axis].value; - // Trigger button press when axis is all the way - int button = (axis == GAMEPAD_AXIS_LEFT_TRIGGER) ? GAMEPAD_BUTTON_LEFT_TRIGGER_2 : GAMEPAD_BUTTON_RIGHT_TRIGGER_2; - int pressed = (platform.minigamepad.gamepads[gamepadIndex].axes[gamepad_event.axis].value >= 1.0f); + // Trigger button press when axis is all the way + int button = (axis == GAMEPAD_AXIS_LEFT_TRIGGER) ? GAMEPAD_BUTTON_LEFT_TRIGGER_2 : GAMEPAD_BUTTON_RIGHT_TRIGGER_2; + int pressed = (platform.minigamepad.gamepads[gamepadIndex].axes[gamepad_event.axis].value >= 1.0f); - CORE.Input.Gamepad.currentButtonState[gamepadIndex][button] = pressed; - if (pressed) CORE.Input.Gamepad.lastButtonPressed = button; - else if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0; - break; - } - } break; + CORE.Input.Gamepad.currentButtonState[gamepadIndex][button] = pressed; + if (pressed) CORE.Input.Gamepad.lastButtonPressed = button; + else if (CORE.Input.Gamepad.lastButtonPressed == button) CORE.Input.Gamepad.lastButtonPressed = 0; + } break; + default: break; + } + } break; case MG_EVENT_GAMEPAD_CONNECT: + { CORE.Input.Gamepad.ready[gamepadIndex] = true; CORE.Input.Gamepad.axisState[gamepadIndex][GAMEPAD_AXIS_LEFT_TRIGGER] = -1.0f; CORE.Input.Gamepad.axisState[gamepadIndex][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f; int axisCount = 0; - for (int i = 0; i < MG_AXIS_COUNT; i += 1) { - if (platform.minigamepad.gamepads[gamepadIndex].axes[i].supported) - { - axisCount += 1; - } - else - { - break; - } + for (int i = 0; i < MG_AXIS_COUNT; i += 1) + { + if (platform.minigamepad.gamepads[gamepadIndex].axes[i].supported) axisCount += 1; + else break; } + CORE.Input.Gamepad.axisCount[gamepadIndex] = axisCount; - strcpy(CORE.Input.Gamepad.name[gamepadIndex], platform.minigamepad.gamepads[gamepadIndex].name); - break; - case MG_EVENT_GAMEPAD_DISCONNECT: - CORE.Input.Gamepad.ready[gamepadIndex] = false; - break; + snprintf(CORE.Input.Gamepad.name[gamepadIndex], MAX_GAMEPAD_NAME_LENGTH, "%s", platform.minigamepad.gamepads[gamepadIndex].name); + + } break; + case MG_EVENT_GAMEPAD_DISCONNECT: CORE.Input.Gamepad.ready[gamepadIndex] = false; break; default: break; } } diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 8fd67b6d0..130d0c184 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -1512,9 +1512,9 @@ void PollInputEvents(void) // Event memory is now managed by SDL, so it should not be freed in SDL_EVENT_DROP_FILE, // in case data needs to be hold onto the text in SDL_EVENT_TEXT_EDITING and SDL_EVENT_TEXT_INPUT events, // a copy is required, SDL_TEXTINPUTEVENT_TEXT_SIZE is no longer necessary and has been removed - strncpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data, MAX_FILEPATH_LENGTH - 1); + snprintf(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], MAX_FILEPATH_LENGTH, "%s", event.drop.data); #else - strncpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file, MAX_FILEPATH_LENGTH - 1); + snprintf(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], MAX_FILEPATH_LENGTH, "%s", event.drop.file); SDL_free(event.drop.file); #endif @@ -1525,9 +1525,9 @@ void PollInputEvents(void) CORE.Window.dropFilepaths[CORE.Window.dropFileCount] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); #if defined(USING_VERSION_SDL3) - strncpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.data, MAX_FILEPATH_LENGTH - 1); + snprintf(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], MAX_FILEPATH_LENGTH, "%s", event.drop.data); #else - strncpy(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], event.drop.file, MAX_FILEPATH_LENGTH - 1); + snprintf(CORE.Window.dropFilepaths[CORE.Window.dropFileCount], MAX_FILEPATH_LENGTH, "%s", event.drop.file); SDL_free(event.drop.file); #endif @@ -1812,8 +1812,8 @@ void PollInputEvents(void) CORE.Input.Gamepad.axisState[nextAvailableSlot][GAMEPAD_AXIS_RIGHT_TRIGGER] = -1.0f; memset(CORE.Input.Gamepad.name[nextAvailableSlot], 0, MAX_GAMEPAD_NAME_LENGTH); const char *controllerName = SDL_GameControllerNameForIndex(nextAvailableSlot); - if (controllerName != NULL) strncpy(CORE.Input.Gamepad.name[nextAvailableSlot], controllerName, MAX_GAMEPAD_NAME_LENGTH - 1); - else strncpy(CORE.Input.Gamepad.name[nextAvailableSlot], "noname", 6); + if (controllerName != NULL) snprintf(CORE.Input.Gamepad.name[nextAvailableSlot], MAX_GAMEPAD_NAME_LENGTH, "%s", controllerName); + else memcpy(CORE.Input.Gamepad.name[nextAvailableSlot], "noname", 6); } else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError()); } @@ -2191,7 +2191,7 @@ int InitPlatform(void) #else const char *joystickName = SDL_GameControllerNameForIndex(i); #endif - strncpy(CORE.Input.Gamepad.name[i], joystickName, MAX_GAMEPAD_NAME_LENGTH - 1); + snprintf(CORE.Input.Gamepad.name[i], MAX_GAMEPAD_NAME_LENGTH, "%s", joystickName); CORE.Input.Gamepad.name[i][MAX_GAMEPAD_NAME_LENGTH - 1] = '\0'; } else TRACELOG(LOG_WARNING, "PLATFORM: Unable to open game controller [ERROR: %s]", SDL_GetError()); diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c index 9d16c3e87..dcc83accf 100644 --- a/src/platforms/rcore_web.c +++ b/src/platforms/rcore_web.c @@ -1579,7 +1579,7 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) { CORE.Window.dropFilepaths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); - strncpy(CORE.Window.dropFilepaths[i], paths[i], MAX_FILEPATH_LENGTH - 1); + snprintf(CORE.Window.dropFilepaths[i], MAX_FILEPATH_LENGTH, "%s", paths[i]); } } } diff --git a/src/platforms/rcore_web_emscripten.c b/src/platforms/rcore_web_emscripten.c index ff78ac547..28f26f861 100644 --- a/src/platforms/rcore_web_emscripten.c +++ b/src/platforms/rcore_web_emscripten.c @@ -1439,7 +1439,7 @@ static void WindowDropCallback(GLFWwindow *window, int count, const char **paths for (unsigned int i = 0; i < CORE.Window.dropFileCount; i++) { CORE.Window.dropFilepaths[i] = (char *)RL_CALLOC(MAX_FILEPATH_LENGTH, sizeof(char)); - strncpy(CORE.Window.dropFilepaths[i], paths[i], MAX_FILEPATH_LENGTH - 1); + snprintf(CORE.Window.dropFilepaths[i], MAX_FILEPATH_LENGTH, "%s", paths[i]); } } } diff --git a/src/raudio.c b/src/raudio.c index 094ea7533..77b6060c8 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -1154,7 +1154,7 @@ bool ExportWaveAsCode(Wave wave, const char *fileName) // Get file name from path and convert variable name to uppercase char varFileName[256] = { 0 }; - strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1); + snprintf(varFileName, 256, "%s", GetFileNameWithoutExt(fileName)); // NOTE: Using function provided by [rcore] module for (int i = 0; varFileName[i] != '\0'; i++) if (varFileName[i] >= 'a' && varFileName[i] <= 'z') { varFileName[i] = varFileName[i] - 32; } // Add wave information @@ -2827,7 +2827,7 @@ static const char *GetFileNameWithoutExt(const char *filePath) static char fileName[MAX_FILENAMEWITHOUTEXT_LENGTH] = { 0 }; memset(fileName, 0, MAX_FILENAMEWITHOUTEXT_LENGTH); - if (filePath != NULL) strncpy(fileName, GetFileName(filePath), MAX_FILENAMEWITHOUTEXT_LENGTH - 1); // Get filename with extension + if (filePath != NULL) snprintf(fileName, MAX_FILENAMEWITHOUTEXT_LENGTH, "%s", GetFileName(filePath)); int fileNameLength = (int)strlen(fileName); // Get size in bytes diff --git a/src/rcore.c b/src/rcore.c index d1163a515..1f987b233 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -108,7 +108,7 @@ #include // Required for: srand(), rand(), exit() #include // Required for: FILE, fopen(), fseek(), ftell(), fread(), fwrite(), fprintf(), vprintf(), fclose(), sprintf() [Used in OpenURL()] -#include // Required for: strlen(), strncpy(), strcmp(), strrchr(), memset(), strcat() +#include // Required for: strlen(), strcmp(), strrchr(), memset(), memcpy(), strcat() #include // Required for: va_list, va_start(), va_end() [Used in TraceLog()] #include // Required for: time() [Used in InitTimer()] #include // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoConfig()] @@ -1819,7 +1819,7 @@ void TakeScreenshot(const char *fileName) Image image = { imgData, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y), 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; char path[MAX_FILEPATH_LENGTH] = { 0 }; - strncpy(path, TextFormat("%s/%s", CORE.Storage.basePath, fileName), MAX_FILEPATH_LENGTH - 1); + snprintf(path, MAX_FILEPATH_LENGTH, "%s", TextFormat("%s/%s", CORE.Storage.basePath, fileName)); ExportImage(image, path); // WARNING: Module required: rtextures RL_FREE(imgData); @@ -1885,12 +1885,12 @@ void TraceLog(int logType, const char *text, ...) switch (logType) { - case LOG_TRACE: strncpy(buffer, "TRACE: ", 8); break; - case LOG_DEBUG: strncpy(buffer, "DEBUG: ", 8); break; - case LOG_INFO: strncpy(buffer, "INFO: ", 7); break; - case LOG_WARNING: strncpy(buffer, "WARNING: ", 10); break; - case LOG_ERROR: strncpy(buffer, "ERROR: ", 8); break; - case LOG_FATAL: strncpy(buffer, "FATAL: ", 8); break; + case LOG_TRACE: memcpy(buffer, "TRACE: ", 7); break; + case LOG_DEBUG: memcpy(buffer, "DEBUG: ", 7); break; + case LOG_INFO: memcpy(buffer, "INFO: ", 6); break; + case LOG_WARNING: memcpy(buffer, "WARNING: ", 9); break; + case LOG_ERROR: memcpy(buffer, "ERROR: ", 7); break; + case LOG_FATAL: memcpy(buffer, "FATAL: ", 7); break; default: break; } @@ -2063,7 +2063,7 @@ bool ExportDataAsCode(const unsigned char *data, int dataSize, const char *fileN // Get file name from path char varFileName[256] = { 0 }; - strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1); + snprintf(varFileName, 256, "%s", GetFileNameWithoutExt(fileName)); for (int i = 0; varFileName[i] != '\0'; i++) { // Convert variable name to uppercase @@ -2507,7 +2507,7 @@ const char *GetFileNameWithoutExt(const char *filePath) if (filePath != NULL) { - strncpy(fileName, GetFileName(filePath), MAX_FILENAME_LENGTH - 1); // Get filename.ext without path + snprintf(fileName, MAX_FILENAME_LENGTH, "%s", GetFileName(filePath)); // Get filename.ext without path int fileNameLength = (int)strlen(fileName); // Get size in bytes for (int i = fileNameLength; i > 0; i--) // Reverse search '.' @@ -2561,7 +2561,6 @@ const char *GetDirectoryPath(const char *filePath) } else { - // NOTE: Be careful, strncpy() is not safe, it does not care about '\0' char *dirPathPtr = dirPath; if ((filePath[1] != ':') && (filePath[0] != '\\') && (filePath[0] != '/')) dirPathPtr += 2; // Skip drive letter, "C:" memcpy(dirPathPtr, filePath, strlen(filePath) - (strlen(lastSlash) - 1)); @@ -2579,7 +2578,7 @@ const char *GetPrevDirectoryPath(const char *dirPath) memset(prevDirPath, 0, MAX_FILEPATH_LENGTH); int dirPathLength = (int)strlen(dirPath); - if (dirPathLength <= 3) strncpy(prevDirPath, dirPath, MAX_FILEPATH_LENGTH - 1); + if (dirPathLength <= 3) snprintf(prevDirPath, MAX_FILEPATH_LENGTH, "%s", dirPath); for (int i = (dirPathLength - 1); (i >= 0) && (dirPathLength > 3); i--) { @@ -2588,7 +2587,7 @@ const char *GetPrevDirectoryPath(const char *dirPath) // Check for root: "C:\" or "/" if (((i == 2) && (dirPath[1] ==':')) || (i == 0)) i++; - strncpy(prevDirPath, dirPath, i); + memcpy(prevDirPath, dirPath, i); break; } } diff --git a/src/rlgl.h b/src/rlgl.h index d72469e11..de8f12d1a 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -2469,7 +2469,7 @@ void rlLoadExtensions(void *loader) // NOTE: String duplication rquired because glGetString() returns a const string int extensionsLength = (int)strlen(extensions); // Get extensions string size in bytes char *extensionsDup = (char *)RL_CALLOC(extensionsLength + 1, sizeof(char)); // Allocate space for copy with additional EOL byte - strncpy(extensionsDup, extensions, extensionsLength); + snprintf(extensionsDup, extensionsLength, "%s", extensions); extList[numExt] = extensionsDup; for (int i = 0; i < extensionsLength; i++) diff --git a/src/rmodels.c b/src/rmodels.c index 28fb3c9ec..ad00225d7 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -50,9 +50,9 @@ #include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 #include "raymath.h" // Required for: Vector3, Quaternion and Matrix functionality -#include // Required for: sprintf() +#include // Required for: sprintf(), snprintf() #include // Required for: malloc(), calloc(), free() -#include // Required for: memcmp(), strlen(), strncpy() +#include // Required for: strlen(), memcmp() #include // Required for: sinf(), cosf(), sqrtf(), fabsf() #if SUPPORT_FILEFORMAT_OBJ || SUPPORT_FILEFORMAT_MTL @@ -2073,7 +2073,7 @@ bool ExportMeshAsCode(Mesh mesh, const char *fileName) // Get file name from path and convert variable name to uppercase char varFileName[256] = { 0 }; - strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1); // NOTE: Using function provided by [rcore] module + snprintf(varFileName, 256, "%s", GetFileNameWithoutExt(fileName)); // NOTE: Using function provided by [rcore] module for (int i = 0; varFileName[i] != '\0'; i++) if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; } // Add image information @@ -4421,7 +4421,7 @@ static Model LoadOBJ(const char *fileName) } char currentDir[MAX_FILEPATH_LENGTH] = { 0 }; - strncpy(currentDir, GetWorkingDirectory(), MAX_FILEPATH_LENGTH - 1); // Save current working directory + snprintf(currentDir, MAX_FILEPATH_LENGTH, "%s", GetWorkingDirectory()); // Save current working directory const char *workingDir = GetDirectoryPath(fileName); // Switch to OBJ directory for material path correctness if (CHDIR(workingDir) != 0) TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to change working directory", workingDir); @@ -5377,7 +5377,7 @@ static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, int *boneCount) for (unsigned int i = 0; i < skin.joints_count; i++) { cgltf_node node = *skin.joints[i]; - if (node.name != NULL) strncpy(bones[i].name, node.name, sizeof(bones[i].name) - 1); + if (node.name != NULL) snprintf(bones[i].name, sizeof(bones[i].name), "%s", node.name); // Find parent bone index by walking up the node tree past any // non-joint ancestors (intermediate transform nodes used by some @@ -6660,7 +6660,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo animDuration = (time > animDuration)? time : animDuration; } - if (animData.name != NULL) strncpy(animations[a].name, animData.name, sizeof(animations[a].name) - 1); + if (animData.name != NULL) snprintf(animations[a].name, sizeof(animations[a].name), "%s", animData.name); animations[a].keyframeCount = (int)(animDuration*GLTF_FRAMERATE) + 1; animations[a].keyframePoses = (Transform **)RL_CALLOC(animations[a].keyframeCount, sizeof(Transform *)); @@ -7150,7 +7150,7 @@ static Model LoadM3D(const char *fileName) for (i = 0; i < (int)m3d->numbone; i++) { model.skeleton.bones[i].parent = m3d->bone[i].parent; - strncpy(model.skeleton.bones[i].name, m3d->bone[i].name, sizeof(model.skeleton.bones[i].name) - 1); + snprintf(model.skeleton.bones[i].name, sizeof(model.skeleton.bones[i].name), "%s", m3d->bone[i].name); model.skeleton.bindPose[i].translation.x = m3d->vertex[m3d->bone[i].pos].x*m3d->scale; model.skeleton.bindPose[i].translation.y = m3d->vertex[m3d->bone[i].pos].y*m3d->scale; model.skeleton.bindPose[i].translation.z = m3d->vertex[m3d->bone[i].pos].z*m3d->scale; @@ -7258,14 +7258,14 @@ static ModelAnimation *LoadModelAnimationsM3D(const char *fileName, int *animCou animations[a].keyframeCount = m3d->action[a].durationmsec/M3D_ANIMDELAY; animations[a].keyframePoses = (Transform **)RL_CALLOC(animations[a].keyframeCount, sizeof(Transform *)); - strncpy(animations[a].name, m3d->action[a].name, sizeof(animations[a].name) - 1); + snprintf(animations[a].name, sizeof(animations[a].name), "%s", m3d->action[a].name); TRACELOG(LOG_INFO, "MODEL: [%s] Loaded animation: %s | Frames: %d | Duration: %fs", fileName, animations[a].name, animations[a].keyframeCount, m3d->action[a].durationmsec); for (i = 0; i < (int)m3d->numbone; i++) { bones[i].parent = m3d->bone[i].parent; - strncpy(bones[i].name, m3d->bone[i].name, sizeof(bones[i].name) - 1); + snprintf(bones[i].name, sizeof(bones[i].name), "%s", m3d->bone[i].name); } // A special, never transformed "no bone" bone, used for boneless vertices diff --git a/src/rtext.c b/src/rtext.c index 9d5943ce8..acd1a5433 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -58,8 +58,8 @@ #include "rlgl.h" // OpenGL abstraction layer to OpenGL 1.1, 2.1, 3.3+ or ES2 -> Only DrawTextPro() #include // Required for: malloc(), free() -#include // Required for: vsprintf() -#include // Required for: strcmp(), strstr(), strncpy() [Used in TextReplace()], sscanf() [Used in LoadBMFont()] +#include // Required for: vsprintf(), snprintf() +#include // Required for: strcmp(), strstr(), strncpy(), sscanf() [Used in LoadBMFont()] #include // Required for: va_list, va_start(), vsprintf(), va_end() [Used in TextFormat()] #include // Required for: toupper(), tolower() [Used in TextToUpper(), TextToLower()] @@ -536,7 +536,7 @@ Font LoadFontFromMemory(const char *fileType, const unsigned char *fileData, int Font font = { 0 }; char fileExtLower[16] = { 0 }; - strncpy(fileExtLower, TextToLower(fileType), 16 - 1); + snprintf(fileExtLower, 16, "%s", TextToLower(fileType)); font.baseSize = fontSize; font.glyphPadding = 0; @@ -1030,7 +1030,7 @@ bool ExportFontAsCode(Font font, const char *fileName) // Get file name from path char fileNamePascal[256] = { 0 }; - strncpy(fileNamePascal, TextToPascal(GetFileNameWithoutExt(fileName)), 256 - 1); + snprintf(fileNamePascal, 256, "%s", TextToPascal(GetFileNameWithoutExt(fileName))); // Get font atlas image and size, required to estimate code file size // NOTE: This mechanism is highly coupled to raylib @@ -1532,7 +1532,7 @@ char **LoadTextLines(const char *text, int *count) if ((text[i] == '\n') || (text[i] == '\0')) { lines[l] = (char *)RL_CALLOC(lineLen + 1, 1); - strncpy(lines[l], &text[i - lineLen], lineLen); + memcpy(lines[l], &text[i - lineLen], lineLen); lineLen = 0; l++; } @@ -1755,8 +1755,8 @@ char *GetTextBetween(const char *text, const char *begin, const char *end) { endIndex += (beginIndex + beginLen); int len = (endIndex - beginIndex - beginLen); - if (len < (MAX_TEXT_BUFFER_LENGTH - 1)) strncpy(buffer, text + beginIndex + beginLen, len); - else strncpy(buffer, text + beginIndex + beginLen, MAX_TEXT_BUFFER_LENGTH - 1); + if (len < (MAX_TEXT_BUFFER_LENGTH - 1)) memcpy(buffer, text + beginIndex + beginLen, len); + else snprintf(buffer, MAX_TEXT_BUFFER_LENGTH, "%s", text + beginIndex + beginLen); } } @@ -1764,7 +1764,7 @@ char *GetTextBetween(const char *text, const char *begin, const char *end) } // Replace text string -// REQUIRES: strstr(), strncpy() +// REQUIRES: strstr(), memcpy() // NOTE: Limited text replace functionality, using static string char *TextReplace(const char *text, const char *search, const char *replacement) { @@ -1821,7 +1821,7 @@ char *TextReplace(const char *text, const char *search, const char *replacement) // Copy remaind text part after replacement to result (pointed by moving temp) // NOTE: Text pointer internal copy has been updated along the process - strncpy(tempPtr, text, TextLength(text)); + memcpy(tempPtr, text, TextLength(text)); } else TRACELOG(LOG_WARNING, "Text with replacement is longer than internal buffer, use TextReplaceAlloc()"); } @@ -1830,7 +1830,7 @@ char *TextReplace(const char *text, const char *search, const char *replacement) } // Replace text string -// REQUIRES: strstr(), strncpy() +// REQUIRES: strstr(), memcpy() // WARNING: Allocated memory must be manually freed char *TextReplaceAlloc(const char *text, const char *search, const char *replacement) { @@ -1887,7 +1887,7 @@ char *TextReplaceAlloc(const char *text, const char *search, const char *replace // Copy remaind text part after replacement to result (pointed by moving temp) // NOTE: Text pointer internal copy has been updated along the process - strncpy(temp, text, TextLength(text)); + memcpy(temp, text, TextLength(text)); } } diff --git a/src/rtextures.c b/src/rtextures.c index 41ee1ffd1..219067a66 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -813,7 +813,7 @@ bool ExportImageAsCode(Image image, const char *fileName) // Get file name from path and convert variable name to uppercase char varFileName[256] = { 0 }; - strncpy(varFileName, GetFileNameWithoutExt(fileName), 256 - 1); // NOTE: Using function provided by [rcore] module + snprintf(varFileName, 256, "%s", GetFileNameWithoutExt(fileName)); // NOTE: Using function provided by [rcore] module for (int i = 0; varFileName[i] != '\0'; i++) if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; } // Add image information diff --git a/tools/rexm/rexm.c b/tools/rexm/rexm.c index f268a7d44..cb753e031 100644 --- a/tools/rexm/rexm.c +++ b/tools/rexm/rexm.c @@ -2331,7 +2331,7 @@ static rlExampleInfo *LoadExampleInfo(const char *exFileName) // Example found in collection exInfo = (rlExampleInfo *)RL_CALLOC(1, sizeof(rlExampleInfo)); - strncpy(exInfo->name, GetFileNameWithoutExt(exFileName), 128 - 1); + snprintf(exInfo->name, 128, "%s", GetFileNameWithoutExt(exFileName)); strncpy(exInfo->category, exInfo->name, TextFindIndex(exInfo->name, "_")); char *exText = LoadFileText(exFileName); @@ -2377,7 +2377,7 @@ static rlExampleInfo *LoadExampleInfo(const char *exFileName) int copyrightIndex = TextFindIndex(exText, "Copyright (c) "); int yearStartIndex = copyrightIndex + 14; char yearText[5] = { 0 }; - strncpy(yearText, exText + yearStartIndex, 4); + snprintf(yearText, 5, "%s", exText + yearStartIndex); exInfo->yearCreated = TextToInteger(yearText); // Check for review year included (or just use creation year) if (exText[yearStartIndex + 4] == '-') strncpy(yearText, exText + yearStartIndex + 5, 4); @@ -2425,7 +2425,7 @@ static int ParseExampleInfoLine(const char *line, rlExampleInfo *entry) #define MAX_EXAMPLE_INFO_LINE_LEN 512 char temp[MAX_EXAMPLE_INFO_LINE_LEN] = { 0 }; - strncpy(temp, line, MAX_EXAMPLE_INFO_LINE_LEN); + snprintf(temp, MAX_EXAMPLE_INFO_LINE_LEN, "%s", line); temp[MAX_EXAMPLE_INFO_LINE_LEN - 1] = '\0'; // Ensure null termination int tokenCount = 0; @@ -2902,7 +2902,7 @@ static void UpdateWebMetadata(const char *exHtmlPath, const char *exFilePath) char exTitle[64] = { 0 }; // Example title: fileName without extension, replacing underscores by spaces // Get example name: replace underscore by spaces - strncpy(exName, GetFileNameWithoutExt(exHtmlPathCopy), 64 - 1); + snprintf(exName, 64, "%s", GetFileNameWithoutExt(exHtmlPathCopy)); strcpy(exTitle, exName); for (int i = 0; (i < 64) && (exTitle[i] != '\0'); i++) { if (exTitle[i] == '_') exTitle[i] = ' '; } From f8e42cb5099141f5a716b2d91b2125fb450e04c3 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 7 Jul 2026 11:45:30 +0200 Subject: [PATCH 36/94] REVIEWED: `OpenURL()`, added some safety checks to mitigate possible malicious url inputs --- src/platforms/rcore_android.c | 17 +++++++++++++---- src/platforms/rcore_desktop_glfw.c | 24 +++++++++++++++++------- src/platforms/rcore_desktop_rgfw.c | 22 ++++++++++++++++------ src/platforms/rcore_desktop_sdl.c | 18 +++++++++++++----- src/platforms/rcore_desktop_win32.c | 25 +++++++++++++++++-------- src/platforms/rcore_drm.c | 5 ++--- src/platforms/rcore_template.c | 20 ++++++++++++++------ src/platforms/rcore_web_emscripten.c | 19 ++++++++++++++----- src/rcore.c | 2 -- 9 files changed, 106 insertions(+), 46 deletions(-) diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c index 78abe9ed6..15d870b10 100644 --- a/src/platforms/rcore_android.c +++ b/src/platforms/rcore_android.c @@ -663,13 +663,22 @@ double GetTime(void) } // Open URL with default system browser (if available) -// NOTE: This function is only safe to use if the provided URL is safe -// A user could craft a malicious string performing another action -// Avoid calling this function with user input non-validated strings +// WARNING: This function is only safe to use if you control the URL given, +// a user could craft a malicious string to perform and undesired action +// NOTE: Some safety checks have been added to mitigate security issues void OpenURL(const char *url) { // Security check to (partially) avoid malicious code - if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); + if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL)) + { + // Filter characters: ' and " + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); + } + else if ((strncmp(url, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + { + // Only allow URL starting with "http://" or "https://" protocols + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols"); + } else { JNIEnv *env = NULL; diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index b0bdf70f3..88e02993a 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -1181,17 +1181,25 @@ double GetTime(void) } // Open URL with default system browser (if available) -// NOTE: This function is only safe to use if you control the URL given -// A user could craft a malicious string performing another action -// Only call this function yourself not with user input or make sure to check the string yourself -// REF: https://github.com/raysan5/raylib/issues/686 +// WARNING: This function is only safe to use if you control the URL given, +// a user could craft a malicious string to perform and undesired action +// NOTE: Some safety checks have been added to mitigate security issues void OpenURL(const char *url) { // Security check to (partially) avoid malicious code - if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); - else + if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL)) { - char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char)); + // Filter characters: ' and " + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); + } + else if ((strncmp(url, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + { + // Only allow URL starting with "http://" or "https://" protocols + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols"); + } + else + { + char *cmd = (char *)RL_CALLOC(strlen(url) + 16, sizeof(char)); #if defined(_WIN32) sprintf(cmd, "explorer \"%s\"", url); #endif @@ -1201,7 +1209,9 @@ void OpenURL(const char *url) #if defined(__APPLE__) sprintf(cmd, "open '%s'", url); #endif + // TODO: Replace system() call by custom process int result = system(cmd); + if (result == -1) TRACELOG(LOG_WARNING, "OpenURL() child process could not be created"); RL_FREE(cmd); } diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index 2e973108b..1c1797c48 100644 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -1471,15 +1471,25 @@ double GetTime(void) } // Open URL with default system browser (if available) -// NOTE: This function is only safe to use if you control the URL given -// A user could craft a malicious string performing another action +// WARNING: This function is only safe to use if you control the URL given, +// a user could craft a malicious string to perform and undesired action +// NOTE: Some safety checks have been added to mitigate security issues void OpenURL(const char *url) { - // Security check to (partially) avoid malicious code on target platform - if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); - else + // Security check to (partially) avoid malicious code + if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL)) { - char *cmd = (char *)RL_CALLOC(strlen(url) + 32, sizeof(char)); + // Filter characters: ' and " + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); + } + else if ((strncmp(url, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + { + // Only allow URL starting with "http://" or "https://" protocols + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols"); + } + else + { + char *cmd = (char *)RL_CALLOC(strlen(url) + 16, sizeof(char)); #if defined(_WIN32) sprintf(cmd, "explorer \"%s\"", url); #endif diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 130d0c184..378f9892b 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -1341,14 +1341,22 @@ double GetTime(void) } // Open URL with default system browser (if available) -// NOTE: This function is only safe to use if the provided URL is safe -// A user could craft a malicious string performing another action -// Avoid calling this function with user input non-validated strings -// REF: https://github.com/raysan5/raylib/issues/686 +// WARNING: This function is only safe to use if you control the URL given, +// a user could craft a malicious string to perform and undesired action +// NOTE: Some safety checks have been added to mitigate security issues void OpenURL(const char *url) { // Security check to (partially) avoid malicious code - if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); + if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL)) + { + // Filter characters: ' and " + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); + } + else if ((strncmp(url, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + { + // Only allow URL starting with "http://" or "https://" protocols + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols"); + } else SDL_OpenURL(url); } diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c index 35347023d..efe1cb42d 100644 --- a/src/platforms/rcore_desktop_win32.c +++ b/src/platforms/rcore_desktop_win32.c @@ -1247,19 +1247,28 @@ double GetTime(void) } // Open URL with default system browser (if available) -// NOTE: This function is only safe to use if the provided URL is safe -// A user could craft a malicious string performing another action -// Avoid calling this function with user input non-validated strings -// REF: https://github.com/raysan5/raylib/issues/686 +// WARNING: This function is only safe to use if you control the URL given, +// a user could craft a malicious string to perform and undesired action +// NOTE: Some safety checks have been added to mitigate security issues void OpenURL(const char *url) { - // Security check to (partially) avoid malicious code on target platform - if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); - else + // Security check to (partially) avoid malicious code + if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL)) { - int len = strlen(url) + 32; + // Filter characters: ' and " + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); + } + else if ((strncmp(url, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + { + // Only allow URL starting with "http://" or "https://" protocols + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols"); + } + else + { + int len = strlen(url) + 16; char *cmd = (char *)RL_CALLOC(len, sizeof(char)); snprintf(cmd, len, "explorer \"%s\"", url); + int result = system(cmd); if (result == -1) TRACELOG(LOG_WARNING, "OpenURL() child process could not be created"); RL_FREE(cmd); diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c index 659c80011..5f04a6612 100644 --- a/src/platforms/rcore_drm.c +++ b/src/platforms/rcore_drm.c @@ -1014,9 +1014,8 @@ double GetTime(void) } // Open URL with default system browser (if available) -// NOTE: This function is only safe to use if the provided URL is safe -// A user could craft a malicious string performing another action -// Avoid calling this function with user input non-validated strings +// WARNING: This function is only safe to use if you control the URL given, +// a user could craft a malicious string to perform and undesired action void OpenURL(const char *url) { TRACELOG(LOG_WARNING, "OpenURL() not implemented on target platform"); diff --git a/src/platforms/rcore_template.c b/src/platforms/rcore_template.c index 353d32d11..24fd1ecab 100644 --- a/src/platforms/rcore_template.c +++ b/src/platforms/rcore_template.c @@ -352,14 +352,22 @@ double GetTime(void) } // Open URL with default system browser (if available) -// NOTE: This function is only safe to use if you control the URL given. -// A user could craft a malicious string performing another action. -// Only call this function yourself not with user input or make sure to check the string yourself. -// Ref: https://github.com/raysan5/raylib/issues/686 +// WARNING: This function is only safe to use if you control the URL given, +// a user could craft a malicious string to perform and undesired action +// NOTE: Some safety checks have been added to mitigate security issues void OpenURL(const char *url) { - // Security check to (partially) avoid malicious code on target platform - if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); + // Security check to (partially) avoid malicious code + if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL)) + { + // Filter characters: ' and " + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); + } + else if ((strncmp(url, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + { + // Only allow URL starting with "http://" or "https://" protocols + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols"); + } else { // TODO: Load url using default browser diff --git a/src/platforms/rcore_web_emscripten.c b/src/platforms/rcore_web_emscripten.c index 28f26f861..a7052c206 100644 --- a/src/platforms/rcore_web_emscripten.c +++ b/src/platforms/rcore_web_emscripten.c @@ -968,13 +968,22 @@ double GetTime(void) } // Open URL with default system browser (if available) -// NOTE: This function is only safe to use if the provided URL is safe -// A user could craft a malicious string performing another action -// Avoid calling this function with user input non-validated strings +// WARNING: This function is only safe to use if you control the URL given, +// a user could craft a malicious string to perform and undesired action +// NOTE: Some safety checks have been added to mitigate security issues void OpenURL(const char *url) { - // Security check to (partially) avoid malicious code on target platform - if (strchr(url, '\'') != NULL) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'] character"); + // Security check to (partially) avoid malicious code + if ((strchr(url, '\'') != NULL) || (strchr(url, '\"') != NULL)) + { + // Filter characters: ' and " + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); + } + else if ((strncmp(url, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + { + // Only allow URL starting with "http://" or "https://" protocols + TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols"); + } else emscripten_run_script(TextFormat("window.open('%s', '_blank')", url)); } diff --git a/src/rcore.c b/src/rcore.c index d84d58b8b..00eca6eb1 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1844,8 +1844,6 @@ void SetConfigFlags(unsigned int flags) FLAG_SET(CORE.Window.flags, flags); } -// void OpenURL(const char *url); // Defined per platform - //---------------------------------------------------------------------------------- // Module Functions Definition: Logging system //---------------------------------------------------------------------------------- From 3cb8a3d782094e5a2105307effe53d6e2e8f9d42 Mon Sep 17 00:00:00 2001 From: Jussi Viitala Date: Tue, 7 Jul 2026 12:46:07 +0300 Subject: [PATCH 37/94] ReiLua Lua binding update to raylib 6.0. (#5959) --- BINDINGS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BINDINGS.md b/BINDINGS.md index f528c892a..624ec8155 100644 --- a/BINDINGS.md +++ b/BINDINGS.md @@ -52,7 +52,7 @@ Some people ported raylib to other languages in the form of bindings or wrappers | [KaylibKit](https://codeberg.org/Kenta/KaylibKit) | 4.5 | [Kotlin/native](https://kotlinlang.org) | Zlib | | [raylib-lua](https://github.com/TSnake41/raylib-lua) | 5.5 | [Lua](http://www.lua.org) | ISC | | [raylib-lua-bindings (WIP)](https://github.com/legendaryredfox/raylib-lua-bindings) | 5.5 | [Lua](http://www.lua.org) | ISC | -| [ReiLua](https://github.com/nullstare/ReiLua) | 5.5 | [Lua](http://www.lua.org) | MIT | +| [ReiLua](https://github.com/nullstare/ReiLua) | 6.0 | [Lua](http://www.lua.org) | MIT | | [raylib-lua-sol](https://github.com/RobLoach/raylib-lua-sol) | 5.5 | [Lua](http://www.lua.org) | Zlib | | [raylib-luajit](https://github.com/homma/raylib-luajit) | 5.5 | [Lua](http://www.lua.org) | MIT | | [raylib-luajit-generated](https://github.com/james2doyle/raylib-luajit-generated) | 5.5 | [Lua](http://www.lua.org) | MIT | From 81b740403a0696ea9d7bf1fd5ecb87ce09cfe273 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 7 Jul 2026 11:47:19 +0200 Subject: [PATCH 38/94] Updated --- src/platforms/rcore_android.c | 2 +- src/platforms/rcore_desktop_glfw.c | 2 +- src/platforms/rcore_desktop_rgfw.c | 2 +- src/platforms/rcore_desktop_sdl.c | 2 +- src/platforms/rcore_desktop_win32.c | 2 +- src/platforms/rcore_template.c | 2 +- src/platforms/rcore_web_emscripten.c | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c index 15d870b10..f88f53c4c 100644 --- a/src/platforms/rcore_android.c +++ b/src/platforms/rcore_android.c @@ -674,7 +674,7 @@ void OpenURL(const char *url) // Filter characters: ' and " TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); } - else if ((strncmp(url, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + else if ((strncmp(url, "http://", 7) != 0) && (strncmp(url, "https://", 8) != 0)) { // Only allow URL starting with "http://" or "https://" protocols TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols"); diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index 88e02993a..6fd5096f8 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -1192,7 +1192,7 @@ void OpenURL(const char *url) // Filter characters: ' and " TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); } - else if ((strncmp(url, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + else if ((strncmp(url, "http://", 7) != 0) && (strncmp(url, "https://", 8) != 0)) { // Only allow URL starting with "http://" or "https://" protocols TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols"); diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index 1c1797c48..814eda553 100644 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -1482,7 +1482,7 @@ void OpenURL(const char *url) // Filter characters: ' and " TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); } - else if ((strncmp(url, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + else if ((strncmp(url, "http://", 7) != 0) && (strncmp(url, "https://", 8) != 0)) { // Only allow URL starting with "http://" or "https://" protocols TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols"); diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 378f9892b..f51eedd97 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -1352,7 +1352,7 @@ void OpenURL(const char *url) // Filter characters: ' and " TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); } - else if ((strncmp(url, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + else if ((strncmp(url, "http://", 7) != 0) && (strncmp(url, "https://", 8) != 0)) { // Only allow URL starting with "http://" or "https://" protocols TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols"); diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c index efe1cb42d..00d5565e2 100644 --- a/src/platforms/rcore_desktop_win32.c +++ b/src/platforms/rcore_desktop_win32.c @@ -1258,7 +1258,7 @@ void OpenURL(const char *url) // Filter characters: ' and " TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); } - else if ((strncmp(url, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + else if ((strncmp(url, "http://", 7) != 0) && (strncmp(url, "https://", 8) != 0)) { // Only allow URL starting with "http://" or "https://" protocols TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols"); diff --git a/src/platforms/rcore_template.c b/src/platforms/rcore_template.c index 24fd1ecab..216c49af8 100644 --- a/src/platforms/rcore_template.c +++ b/src/platforms/rcore_template.c @@ -363,7 +363,7 @@ void OpenURL(const char *url) // Filter characters: ' and " TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); } - else if ((strncmp(url, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + else if ((strncmp(url, "http://", 7) != 0) && (strncmp(url, "https://", 8) != 0)) { // Only allow URL starting with "http://" or "https://" protocols TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols"); diff --git a/src/platforms/rcore_web_emscripten.c b/src/platforms/rcore_web_emscripten.c index a7052c206..ff10fabb3 100644 --- a/src/platforms/rcore_web_emscripten.c +++ b/src/platforms/rcore_web_emscripten.c @@ -979,7 +979,7 @@ void OpenURL(const char *url) // Filter characters: ' and " TRACELOG(LOG_WARNING, "SYSTEM: Provided URL could be potentially malicious, avoid [\'\"] characters"); } - else if ((strncmp(url, "http://", 7) != 0) && (strncmp(protocol, "https://", 8) != 0)) + else if ((strncmp(url, "http://", 7) != 0) && (strncmp(url, "https://", 8) != 0)) { // Only allow URL starting with "http://" or "https://" protocols TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols"); From d159739a8b92b2789ca4bd64dc82282cb050b0bb Mon Sep 17 00:00:00 2001 From: Nikita Dobrynin Date: Tue, 7 Jul 2026 10:15:54 +0000 Subject: [PATCH 39/94] Fix DRM/EGL segfault on some NVIDIA proprietary drivers (#5960) --- src/platforms/rcore_drm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c index 5f04a6612..6d7278623 100644 --- a/src/platforms/rcore_drm.c +++ b/src/platforms/rcore_drm.c @@ -1445,7 +1445,8 @@ int InitPlatform(void) return -1; } - if (!eglChooseConfig(platform.device, NULL, NULL, 0, &numConfigs)) + // Providing `framebufferAttribs` is not logically necessary, but it may prevent segfaults on some nvidia drivers + if (!eglChooseConfig(platform.device, framebufferAttribs, NULL, 0, &numConfigs)) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to get EGL config count: 0x%x", eglGetError()); return -1; @@ -2731,4 +2732,4 @@ static void SetupFramebuffer(int width, int height) } } -// EOF \ No newline at end of file +// EOF From 3e9fb4757febf045397449b91ed2d91295c6d344 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 7 Jul 2026 12:17:23 +0200 Subject: [PATCH 40/94] Update rcore_drm.c --- src/platforms/rcore_drm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c index 6d7278623..662b52373 100644 --- a/src/platforms/rcore_drm.c +++ b/src/platforms/rcore_drm.c @@ -1445,7 +1445,8 @@ int InitPlatform(void) return -1; } - // Providing `framebufferAttribs` is not logically necessary, but it may prevent segfaults on some nvidia drivers + // WARNING: Providing framebufferAttribs is not logically necessary, + // but it may prevent segfaults on some nvidia drivers if (!eglChooseConfig(platform.device, framebufferAttribs, NULL, 0, &numConfigs)) { TRACELOG(LOG_WARNING, "DISPLAY: Failed to get EGL config count: 0x%x", eglGetError()); From caadb48e259028233515777a3e6402040c497309 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 7 Jul 2026 15:54:57 +0200 Subject: [PATCH 41/94] Update SECURITY.md --- SECURITY.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 48a825e37..7a52e4359 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -11,8 +11,4 @@ Most considerations of errors and defects can be handled using the project Issue ## Reporting a Vulnerability -Discovered vulnerability can be directly reported using the project Issues and/or Discussions. - -_TODO: Tell them where to go, how often they can expect to get an update on a -reported vulnerability, what to expect if the vulnerability is accepted or -declined, etc._ +Discovered vulnerability can be directly reported using the project Issues and/or Discussions. They will be reviewed as soon as possible. From 86c7edfd749f27c0d776b48ab93d065d7c8004dd Mon Sep 17 00:00:00 2001 From: Luis <113704180+LuisR385@users.noreply.github.com> Date: Sat, 11 Jul 2026 19:03:41 +0900 Subject: [PATCH 42/94] [raudio] Fix memory leak when loading .wav files (#5963) * [raudio] Fix memory leak when loading .wav files * [change] Insert a space. --- src/raudio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/raudio.c b/src/raudio.c index 77b6060c8..0a326e030 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -1772,7 +1772,7 @@ void UnloadMusicStream(Music music) { if (false) { } #if SUPPORT_FILEFORMAT_WAV - else if (music.ctxType == MUSIC_AUDIO_WAV) drwav_uninit((drwav *)music.ctxData); + else if (music.ctxType == MUSIC_AUDIO_WAV) { drwav_uninit((drwav *)music.ctxData); RL_FREE(music.ctxData); } #endif #if SUPPORT_FILEFORMAT_OGG else if (music.ctxType == MUSIC_AUDIO_OGG) stb_vorbis_close((stb_vorbis *)music.ctxData); From cba8f4286d5b42ed5e999ba543ca6ebb22d99572 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Louka=20M=C3=A9nard=20Blondin?= Date: Sat, 11 Jul 2026 03:06:54 -0700 Subject: [PATCH 43/94] Fix initial macOS window size (#5967) --- src/platforms/rcore_desktop_glfw.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index 6fd5096f8..f1bf0ae8e 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -1693,6 +1693,14 @@ int InitPlatform(void) return -1; } +#if defined(__APPLE__) + // AppKit can constrain the requested window size to the visible work area during creation + int windowWidth = 0; + int windowHeight = 0; + glfwGetWindowSize(platform.handle, &windowWidth, &windowHeight); + if ((windowWidth > 0) && (windowHeight > 0)) CORE.Window.screen = (Size){ windowWidth, windowHeight }; +#endif + // NOTE: Not considering scale factor now, considered below CORE.Window.render.width = CORE.Window.screen.width; CORE.Window.render.height = CORE.Window.screen.height; From 8df2f13962bdb0f170ab25d9d3b483c2f16772bd Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 11 Jul 2026 12:20:57 +0200 Subject: [PATCH 44/94] Update raudio.c --- src/raudio.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/raudio.c b/src/raudio.c index 0a326e030..42ea410c8 100644 --- a/src/raudio.c +++ b/src/raudio.c @@ -822,7 +822,7 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int wave.sampleRate = wav.sampleRate; wave.sampleSize = 16; wave.channels = wav.channels; - wave.data = (short *)RL_MALLOC((size_t)wave.frameCount*wave.channels*sizeof(short)); + wave.data = (short *)RL_CALLOC((size_t)wave.frameCount*wave.channels, sizeof(short)); // NOTE: Forcing conversion to 16bit sample size on reading drwav_read_pcm_frames_s16(&wav, wave.frameCount, (drwav_int16 *)wave.data); @@ -845,7 +845,7 @@ Wave LoadWaveFromMemory(const char *fileType, const unsigned char *fileData, int wave.sampleSize = 16; // By default, ogg data is 16 bit per sample (short) wave.channels = info.channels; wave.frameCount = (unsigned int)stb_vorbis_stream_length_in_samples(oggData); // NOTE: It returns frames! - wave.data = (short *)RL_MALLOC(wave.frameCount*wave.channels*sizeof(short)); + wave.data = (short *)RL_CALLOC(wave.frameCount*wave.channels, sizeof(short)); // NOTE: Get the number of samples to process (be careful! asking for number of shorts, not bytes!) stb_vorbis_get_samples_short_interleaved(oggData, info.channels, (short *)wave.data, wave.frameCount*wave.channels); @@ -1258,7 +1258,7 @@ void WaveFormat(Wave *wave, int sampleRate, int sampleSize, int channels) return; } - void *data = RL_MALLOC(frameCount*channels*(sampleSize/8)); + void *data = RL_CALLOC(frameCount*channels*(sampleSize/8), 1); frameCount = (ma_uint32)ma_convert_frames(data, frameCount, formatOut, channels, sampleRate, wave->data, frameCountIn, formatIn, wave->channels, wave->sampleRate); if (frameCount == 0) From f458296a075550c34138b9600034f781e7e4059a Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 11 Jul 2026 12:21:24 +0200 Subject: [PATCH 45/94] small optimization --- src/rcore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 00eca6eb1..cfab520bd 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -3273,7 +3273,7 @@ unsigned int *ComputeMD5(const unsigned char *data, int dataSize) memcpy(msg + newDataSize, &bitsLen, 4); // Append the len in bits at the end of the buffer // Process the message in successive 512-bit chunks for each 512-bit chunk of message - for (int offset = 0; offset < newDataSize; offset += (512/8)) + for (int offset = 0; offset < newDataSize; offset += 64) // 512/8 { // Break chunk into sixteen 32-bit words w[j], 0 <= j <= 15 unsigned int *w = (unsigned int *)(msg + offset); @@ -3370,7 +3370,7 @@ unsigned int *ComputeSHA1(const unsigned char *data, int dataSize) msg[newDataSize - 8] = (unsigned char)(bitsLen >> 56); // Process the message in successive 512-bit chunks - for (int offset = 0; offset < newDataSize; offset += (512/8)) + for (int offset = 0; offset < newDataSize; offset += 64) // 512/8 { // Break chunk into sixteen 32-bit words w[j], 0 <= j <= 15 unsigned int w[80] = { 0 }; From c85cd07db00ef3712b335957ab83bfa19f1f3914 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 11 Jul 2026 12:22:03 +0200 Subject: [PATCH 46/94] Update rmodels.c --- src/rmodels.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index dc239b117..7eaceea5f 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -5316,8 +5316,8 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat { int base64Size = (int)strlen(cgltfImage->uri + i + 1); while (cgltfImage->uri[i + base64Size] == '=') base64Size--; // Ignore optional paddings - int numberOfEncodedBits = base64Size*6 - (base64Size*6) % 8 ; // Encoded bits minus extra bits, so it becomes a multiple of 8 bits - int outSize = numberOfEncodedBits/8 ; // Actual encoded bytes + int numberOfEncodedBits = base64Size*6 - (base64Size*6)%8; // Encoded bits minus extra bits, so it becomes a multiple of 8 bits + int outSize = numberOfEncodedBits >> 3; // Actual encoded bytes void *data = NULL; cgltf_options options = { 0 }; From ab35e0f71241d24a3c208228670f8bb0ab1cd324 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 11 Jul 2026 16:18:34 +0200 Subject: [PATCH 47/94] REVIEWED: `LoadAutomationEventList()` - ROS: `CLN-005`, `CLN-006` --- src/rcore.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index cfab520bd..0bf8a5760 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -3601,10 +3601,14 @@ AutomationEventList LoadAutomationEventList(const char *fileName) case 'c': sscanf(buffer, "c %i", &list.count); break; case 'e': { - sscanf(buffer, "e %d %d %d %d %d %d %[^\n]s", &list.events[counter].frame, &list.events[counter].type, - &list.events[counter].params[0], &list.events[counter].params[1], &list.events[counter].params[2], &list.events[counter].params[3], eventDesc); + if (counter < list.capacity) + { + sscanf(buffer, "e %d %d %d %d %d %d %63[^\n]s", &list.events[counter].frame, &list.events[counter].type, + &list.events[counter].params[0], &list.events[counter].params[1], &list.events[counter].params[2], &list.events[counter].params[3], eventDesc); - counter++; + counter++; + } + else TRACELOG(LOG_WARNING, "AUTOMATION: Event goes beyond automated list capacity (MAX: %i): %s", buffer, list.capacity); } break; default: break; } From c31666fe2a5c1e166353807a1e9affcfb165b4a9 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 11 Jul 2026 16:20:41 +0200 Subject: [PATCH 48/94] REVIEWED: `ImageFromImage()` - ROS: `CLN-007` --- src/rtextures.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/rtextures.c b/src/rtextures.c index 219067a66..610b78674 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -1228,18 +1228,25 @@ Image ImageFromImage(Image image, Rectangle rec) { Image result = { 0 }; - int bytesPerPixel = GetPixelDataSize(1, 1, image.format); - - result.width = (int)rec.width; - result.height = (int)rec.height; - result.data = RL_CALLOC((int)rec.width*(int)rec.height*bytesPerPixel, 1); - result.format = image.format; - result.mipmaps = 1; - - for (int y = 0; y < (int)rec.height; y++) + // Basic rectangle validation: size smaller than image size + if ((rec.x > 0) && (rec.y > 0) && (rec.width > 0) && (rec.height > 0) && + (((int)rec.x + (int)rec.width) < image.width) && + (((int)rec.y + (int)rec.height) < image.height)) { - memcpy(((unsigned char *)result.data) + y*(int)rec.width*bytesPerPixel, ((unsigned char *)image.data) + ((y + (int)rec.y)*image.width + (int)rec.x)*bytesPerPixel, (int)rec.width*bytesPerPixel); + int bytesPerPixel = GetPixelDataSize(1, 1, image.format); + + result.width = (int)rec.width; + result.height = (int)rec.height; + result.data = RL_CALLOC((int)rec.width*(int)rec.height*bytesPerPixel, 1); + result.format = image.format; + result.mipmaps = 1; + + for (int y = 0; y < (int)rec.height; y++) + { + memcpy(((unsigned char *)result.data) + y*(int)rec.width*bytesPerPixel, ((unsigned char *)image.data) + ((y + (int)rec.y)*image.width + (int)rec.x)*bytesPerPixel, (int)rec.width*bytesPerPixel); + } } + else TRACELOG(LOG_WARNING, "IMAGE: Rectangle provided for ImageToImage not valid"); return result; } From 97d2b0146c141269bdbbb1192aeb157e47cc5d65 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 11 Jul 2026 16:22:05 +0200 Subject: [PATCH 49/94] REVIEWED: Replace `assert()` by runtime checks - ROS: `CLN-012` --- src/external/tinyobj_loader_c.h | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/external/tinyobj_loader_c.h b/src/external/tinyobj_loader_c.h index 88b2acbdc..8d077d665 100644 --- a/src/external/tinyobj_loader_c.h +++ b/src/external/tinyobj_loader_c.h @@ -1020,7 +1020,12 @@ static int parseLine(Command *command, const char *p, unsigned int p_len, int triangulate) { char linebuf[4096]; const char *token; - assert(p_len < 4095); + + // @raysan5: + // WARNING: If -DNDEBUG is set when compiling, assertions will not + // be present in the compiled binary, replacing by a runtime check + //assert(p_len < 4095); + if (p_len > 4095) return 0; memcpy(linebuf, p, p_len); linebuf[p_len] = '\0'; @@ -1102,8 +1107,12 @@ static int parseLine(Command *command, const char *p, unsigned int p_len, tinyobj_vertex_index_t i1; tinyobj_vertex_index_t i2 = f[1]; - assert(3 * num_f < TINYOBJ_MAX_FACES_PER_F_LINE); - + // @raysan5: + // WARNING: If -DNDEBUG is set when compiling, assertions will not + // be present in the compiled binary, replacing by a runtime check + //assert(3 * num_f < TINYOBJ_MAX_FACES_PER_F_LINE); + if (3*num_f > TINYOBJ_MAX_FACES_PER_F_LINE) return 0; + for (k = 2; k < num_f; k++) { i1 = i2; i2 = f[k]; @@ -1119,7 +1128,13 @@ static int parseLine(Command *command, const char *p, unsigned int p_len, } else { unsigned int k = 0; - assert(num_f < TINYOBJ_MAX_FACES_PER_F_LINE); + + // @raysan5: + // WARNING: If -DNDEBUG is set when compiling, assertions will not + // be present in the compiled binary, replacing by a runtime check + //assert(num_f < TINYOBJ_MAX_FACES_PER_F_LINE); + if (num_f > TINYOBJ_MAX_FACES_PER_F_LINE) return 0; + for (k = 0; k < num_f; k++) { command->f[k] = f[k]; } From cfe56d97ea6b0cf29f4c80f1ebc9e704921a2a10 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 11 Jul 2026 16:42:57 +0200 Subject: [PATCH 50/94] REVIEWED: `GetPixelDataSize()`, avoid allocations >2GB - ROS: `CLN-013` REVIEWED: `GenImageColor()`, `ImageRotate()` --- src/rlgl.h | 18 ++++++++--- src/rtextures.c | 85 ++++++++++++++++++++++++++++--------------------- 2 files changed, 61 insertions(+), 42 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index de8f12d1a..77d7090b0 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -5236,7 +5236,9 @@ static int rlGetPixelDataSize(int width, int height, int format) { int blockWidth = (width + 3)/4; int blockHeight = (height + 3)/4; - dataSize = blockWidth*blockHeight*8; + unsigned long long dataSizeBytes = blockWidth*blockHeight*8; + if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes; + } break; case RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA: case RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA: @@ -5245,13 +5247,17 @@ static int rlGetPixelDataSize(int width, int height, int format) { int blockWidth = (width + 3)/4; int blockHeight = (height + 3)/4; - dataSize = blockWidth*blockHeight*16; + unsigned long long dataSizeBytes = blockWidth*blockHeight*16; + if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes; + } break; case RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: // 4 bytes per each 4x4 block { int blockWidth = (width + 3)/4; int blockHeight = (height + 3)/4; - dataSize = blockWidth*blockHeight*4; + unsigned long long dataSizeBytes = blockWidth*blockHeight*4; + if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes; + } break; default: break; } @@ -5260,9 +5266,11 @@ static int rlGetPixelDataSize(int width, int height, int format) if ((format >= RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) && (format <= RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16)) { - double bytesPerPixel = (double)bpp/8.0; - dataSize = (int)(bytesPerPixel*width*height); // Total data size in bytes + unsigned long long dataSizeBytes = (width*height*bpp) >> 3; // Get size in bytes (dividing by 8) + if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes; } + + if (dataSize == 0) TRACELOG(LOG_WARNING, "Requested image size is larger than 2GB, it can not be allocated"); return dataSize; } diff --git a/src/rtextures.c b/src/rtextures.c index 610b78674..e860df100 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -843,9 +843,10 @@ bool ExportImageAsCode(Image image, const char *fileName) // Generate image: plain color Image GenImageColor(int width, int height, Color color) { - Color *pixels = (Color *)RL_CALLOC(width*height, sizeof(Color)); + int dataSize = GetPixelDataSize(width, height, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8); + Color *pixels = (Color *)RL_CALLOC(dataSize, 1); - for (int i = 0; i < width*height; i++) pixels[i] = color; + for (int i = 0; (pixels != NULL) && (i < width*height); i++) pixels[i] = color; Image image = { .data = pixels, @@ -2691,45 +2692,48 @@ void ImageRotate(Image *image, int degrees) int width = (int)(fabsf(image->width*cosRadius) + fabsf(image->height*sinRadius)); int height = (int)(fabsf(image->height*cosRadius) + fabsf(image->width*sinRadius)); - int bytesPerPixel = GetPixelDataSize(1, 1, image->format); - unsigned char *rotatedData = (unsigned char *)RL_CALLOC(width*height, bytesPerPixel); + int bytesPerPixel = GetPixelDataSize(width, height, image->format); + unsigned char *rotatedData = (unsigned char *)RL_CALLOC(bytesPerPixel, 1); - for (int y = 0; y < height; y++) + if (rotatedData != NULL) { - for (int x = 0; x < width; x++) + for (int y = 0; y < height; y++) { - float oldX = ((x - width/2.0f)*cosRadius + (y - height/2.0f)*sinRadius) + image->width/2.0f; - float oldY = ((y - height/2.0f)*cosRadius - (x - width/2.0f)*sinRadius) + image->height/2.0f; - - if ((oldX >= 0) && (oldX < image->width) && (oldY >= 0) && (oldY < image->height)) + for (int x = 0; x < width; x++) { - int x1 = (int)floorf(oldX); - int y1 = (int)floorf(oldY); - int x2 = MIN(x1 + 1, image->width - 1); - int y2 = MIN(y1 + 1, image->height - 1); + float oldX = ((x - width/2.0f)*cosRadius + (y - height/2.0f)*sinRadius) + image->width/2.0f; + float oldY = ((y - height/2.0f)*cosRadius - (x - width/2.0f)*sinRadius) + image->height/2.0f; - float px = oldX - x1; - float py = oldY - y1; - - for (int i = 0; i < bytesPerPixel; i++) + if ((oldX >= 0) && (oldX < image->width) && (oldY >= 0) && (oldY < image->height)) { - float f1 = ((unsigned char *)image->data)[(y1*image->width + x1)*bytesPerPixel + i]; - float f2 = ((unsigned char *)image->data)[(y1*image->width + x2)*bytesPerPixel + i]; - float f3 = ((unsigned char *)image->data)[(y2*image->width + x1)*bytesPerPixel + i]; - float f4 = ((unsigned char *)image->data)[(y2*image->width + x2)*bytesPerPixel + i]; + int x1 = (int)floorf(oldX); + int y1 = (int)floorf(oldY); + int x2 = MIN(x1 + 1, image->width - 1); + int y2 = MIN(y1 + 1, image->height - 1); - float val = f1*(1 - px)*(1 - py) + f2*px*(1 - py) + f3*(1 - px)*py + f4*px*py; + float px = oldX - x1; + float py = oldY - y1; - rotatedData[(y*width + x)*bytesPerPixel + i] = (unsigned char)val; + for (int i = 0; i < bytesPerPixel; i++) + { + float f1 = ((unsigned char *)image->data)[(y1*image->width + x1)*bytesPerPixel + i]; + float f2 = ((unsigned char *)image->data)[(y1*image->width + x2)*bytesPerPixel + i]; + float f3 = ((unsigned char *)image->data)[(y2*image->width + x1)*bytesPerPixel + i]; + float f4 = ((unsigned char *)image->data)[(y2*image->width + x2)*bytesPerPixel + i]; + + float val = f1*(1 - px)*(1 - py) + f2*px*(1 - py) + f3*(1 - px)*py + f4*px*py; + + rotatedData[(y*width + x)*bytesPerPixel + i] = (unsigned char)val; + } } } } - } - RL_FREE(image->data); - image->data = rotatedData; - image->width = width; - image->height = height; + RL_FREE(image->data); + image->data = rotatedData; + image->width = width; + image->height = height; + } } } @@ -5508,17 +5512,24 @@ int GetPixelDataSize(int width, int height, int format) case PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break; default: break; } + + unsigned long long dataSizeBytes = (width*height*bpp) >> 3; // Get size in bytes (dividing by 8) - double bytesPerPixel = (double)bpp/8.0; - dataSize = (int)(bytesPerPixel*width*height); // Total data size in bytes - - // Most compressed formats works on 4x4 blocks, - // if texture is smaller, minimum dataSize is 8 or 16 - if ((width < 4) && (height < 4)) + if (dataSizeBytes < INT_MAX) { - if ((format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < PIXELFORMAT_COMPRESSED_DXT3_RGBA)) dataSize = 8; - else if ((format >= PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) dataSize = 16; + dataSize = (int)dataSizeBytes; + + // Most compressed formats works on 4x4 blocks, + // if texture is smaller, minimum dataSize is 8 or 16 + if ((width < 4) && (height < 4)) + { + if ((format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) && (format < PIXELFORMAT_COMPRESSED_DXT3_RGBA)) dataSize = 8; + else if ((format >= PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) dataSize = 16; + } } + + // NOTE: In case required image data larger than 2GB, no memory allocated at all (NULL) + if (dataSize == 0) TRACELOG(LOG_WARNING, "Requested image size is larger than 2GB, it can not be allocated"); return dataSize; } From ebec978443efe8d7a46723fb1e4479422e950006 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 11 Jul 2026 16:45:56 +0200 Subject: [PATCH 51/94] REVIEWED: `TextJoin()`, `TextSubtext()`, `TextInsert*()` - ROS: `CLN-018` --- src/rtext.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/rtext.c b/src/rtext.c index acd1a5433..35c6f7307 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -1699,7 +1699,7 @@ const char *TextSubtext(const char *text, int position, int length) static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); - if (text != NULL) + if ((text != NULL) && (position > 0) && (length > 0)) { int textLength = TextLength(text); @@ -1975,10 +1975,11 @@ char *TextInsert(const char *text, const char *insert, int position) { static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); + int textLen = TextLength(text); - if ((text != NULL) && (insert != NULL)) + if ((text != NULL) && (insert != NULL) && (position >= 0)) { - int textLen = TextLength(text); + if (position > textLen) position = textLen; // End of text string int insertLen = TextLength(insert); if ((textLen + insertLen) < (MAX_TEXT_BUFFER_LENGTH - 1)) @@ -1987,7 +1988,7 @@ char *TextInsert(const char *text, const char *insert, int position) for (int i = 0; i < position; i++) buffer[i] = text[i]; for (int i = position; i < insertLen + position; i++) buffer[i] = insert[i - position]; - for (int i = (insertLen + position); i < (textLen + insertLen); i++) buffer[i] = text[i]; + for (int i = (insertLen + position); i < (textLen + insertLen); i++) buffer[i] = text[i - insertLen]; buffer[textLen + insertLen] = '\0'; // Add EOL } @@ -2002,17 +2003,18 @@ char *TextInsert(const char *text, const char *insert, int position) char *TextInsertAlloc(const char *text, const char *insert, int position) { char *result = NULL; + int textLen = TextLength(text); - if ((text != NULL) && (insert != NULL)) + if ((text != NULL) && (insert != NULL) && (position >= 0)) { - int textLen = TextLength(text); + if (position > textLen) position = textLen; // End of text string int insertLen = TextLength(insert); result = (char *)RL_MALLOC(textLen + insertLen + 1); for (int i = 0; i < position; i++) result[i] = text[i]; - for (int i = position; i < insertLen + position; i++) result[i] = insert[i - position]; - for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i]; + for (int i = position; i < (insertLen + position); i++) result[i] = insert[i - position]; + for (int i = (insertLen + position); i < (textLen + insertLen + position); i++) result[i] = text[i - insertLen]; result[textLen + insertLen] = '\0'; // Add EOL } @@ -2036,7 +2038,7 @@ char *TextJoin(char **textList, int count, const char *delimiter) int textLength = TextLength(textList[i]); // Make sure joined text could fit inside MAX_TEXT_BUFFER_LENGTH - if ((totalLength + textLength) < MAX_TEXT_BUFFER_LENGTH) + if ((totalLength + textLength + delimiterLen) < MAX_TEXT_BUFFER_LENGTH) { memcpy(textPtr, textList[i], textLength); totalLength += textLength; From 8805ab3ee2666dbe891a69c52513b2b2ea37c8d7 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 11 Jul 2026 16:57:49 +0200 Subject: [PATCH 52/94] Update rmodels.c --- src/rmodels.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index 7eaceea5f..0325f9b1b 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -2320,7 +2320,7 @@ void UpdateModelAnimation(Model model, ModelAnimation anim, float frame) Matrix currentPoseMatrix = { 0 }; // Update all bones and bone matrices of model - for (int boneIndex = 0; boneIndex < model.skeleton.boneCount; boneIndex++) + for (unsigned int boneIndex = 0; boneIndex < model.skeleton.boneCount; boneIndex++) { // Compute interpolated pose between current and next frame // NOTE: Storing animation frame data in model.currentPose @@ -2390,7 +2390,7 @@ void UpdateModelAnimationEx(Model model, ModelAnimation animA, float frameA, Mod Matrix bindPoseMatrix = { 0 }; Matrix currentPoseMatrix = { 0 }; - for (int boneIndex = 0; boneIndex < model.skeleton.boneCount; boneIndex++) + for (unsigned int boneIndex = 0; boneIndex < model.skeleton.boneCount; boneIndex++) { // Get frame-interpolation for first animation Vector3 frameATranslation = Vector3Lerp( @@ -5013,7 +5013,7 @@ static Model LoadIQM(const char *fileName) // Initialize runtime animation data: current pose and bone matrices model.currentPose = (Transform *)RL_CALLOC(model.skeleton.boneCount, sizeof(Transform)); model.boneMatrices = (Matrix *)RL_CALLOC(model.skeleton.boneCount, sizeof(Matrix)); - for (int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity(); + for (unsigned int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity(); UnloadFileData(fileData); @@ -5241,7 +5241,7 @@ static ModelAnimation *LoadModelAnimationsIQM(const char *fileName, int *animCou // Build frameposes for (unsigned int frame = 0; frame < anim[a].num_frames; frame++) { - for (int i = 0; i < animations[a].boneCount; i++) + for (unsigned int i = 0; i < animations[a].boneCount; i++) { if (bones[i].parent >= 0) { @@ -5371,7 +5371,7 @@ static Image LoadImageFromCgltfImage(cgltf_image *cgltfImage, const char *texPat // Load bone info from GLTF skin data static BoneInfo *LoadBoneInfoGLTF(cgltf_skin skin, unsigned int *boneCount) { - *boneCount = skin.joints_count; + *boneCount = (unsigned int)skin.joints_count; BoneInfo *bones = (BoneInfo *)RL_CALLOC(skin.joints_count, sizeof(BoneInfo)); for (unsigned int i = 0; i < skin.joints_count; i++) @@ -6144,7 +6144,7 @@ static Model LoadGLTF(const char *fileName) model.skeleton.bones = LoadBoneInfoGLTF(skin, &model.skeleton.boneCount); model.skeleton.bindPose = (Transform *)RL_CALLOC(model.skeleton.boneCount, sizeof(Transform)); - for (int i = 0; i < model.skeleton.boneCount; i++) + for (unsigned int i = 0; i < model.skeleton.boneCount; i++) { Matrix bindMatrix = { 0 }; cgltf_float inverseBindTransform[16] = { 0 }; @@ -6309,7 +6309,7 @@ static Model LoadGLTF(const char *fileName) if ((data->skins_count > 0) && !hasJoints && (node->parent != NULL) && (node->parent->mesh == NULL)) { int parentBoneId = -1; - for (int joint = 0; joint < model.skeleton.boneCount; joint++) + for (unsigned int joint = 0; joint < model.skeleton.boneCount; joint++) { if (data->skins[0].joints[joint] == node->parent) { @@ -6347,7 +6347,7 @@ static Model LoadGLTF(const char *fileName) // Initialize runtime animation data: current pose and bone matrices model.currentPose = (Transform *)RL_CALLOC(model.skeleton.boneCount, sizeof(Transform)); model.boneMatrices = (Matrix *)RL_CALLOC(model.skeleton.boneCount, sizeof(Matrix)); - for (int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity(); + for (unsigned int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity(); //---------------------------------------------------------------------------------------------------- // Free unused allocated memory in case of no bones defined @@ -6670,7 +6670,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo animations[a].keyframePoses[j] = (Transform *)RL_CALLOC(animations[a].boneCount, sizeof(Transform)); float time = (float)j / GLTF_FRAMERATE; - for (int k = 0; k < animations[a].boneCount; k++) + for (unsigned int k = 0; k < animations[a].boneCount; k++) { Vector3 translation = {skin.joints[k]->translation[0], skin.joints[k]->translation[1], skin.joints[k]->translation[2]}; Quaternion rotation = {skin.joints[k]->rotation[0], skin.joints[k]->rotation[1], skin.joints[k]->rotation[2], skin.joints[k]->rotation[3]}; @@ -7204,7 +7204,7 @@ static Model LoadM3D(const char *fileName) // Initialize runtime animation data: current pose and bone matrices model.currentPose = (Transform *)RL_CALLOC(model.skeleton.boneCount, sizeof(Transform)); model.boneMatrices = (Matrix *)RL_CALLOC(model.skeleton.boneCount, sizeof(Matrix)); - for (int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity(); + for (unsigned int j = 0; j < model.skeleton.boneCount; j++) model.boneMatrices[j] = MatrixIdentity(); } m3d_free(m3d); From f00317bead662c6e7fd5dfc92f16ca37f8a2e08f Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 11 Jul 2026 17:01:09 +0200 Subject: [PATCH 53/94] Added required library --- src/rlgl.h | 15 ++++++++------- src/rtextures.c | 1 + 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index 77d7090b0..3d4a54d6f 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -847,11 +847,11 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad #define SW_CALLOC(n,sz) RL_CALLOC(n, sz) #define SW_REALLOC(ptr, newSz) RL_REALLOC(ptr, newSz) #define SW_FREE(ptr) RL_FREE(ptr) - #include "external/rlsw.h" // OpenGL 1.1 software implementation + #include "external/rlsw.h" // OpenGL 1.1 software implementation #else #if defined(__APPLE__) - #include // OpenGL 1.1 library for OSX - #include // OpenGL extensions library + #include // OpenGL 1.1 library for OSX + #include // OpenGL extensions library #else // APIENTRY for OpenGL function pointer declarations is required #if !defined(APIENTRY) @@ -866,7 +866,7 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad #define WINGDIAPI __declspec(dllimport) #endif - #include // OpenGL 1.1 library + #include // OpenGL 1.1 library #endif #endif #endif @@ -907,9 +907,10 @@ RLAPI void rlLoadDrawQuad(void); // Load and draw a quad #endif #endif -#include // Required for: calloc(), free() -#include // Required for: strcmp(), strlen() [Used in rlglInit(), on extensions loading] -#include // Required for: sqrtf(), sinf(), cosf(), floor(), log() +#include // Required for: calloc(), free() +#include // Required for: strcmp(), strlen() [Used in rlglInit(), on extensions loading] +#include // Required for: sqrtf(), sinf(), cosf(), floor(), log() +#include // Required for: INT_MAX //---------------------------------------------------------------------------------- // Defines and Macros diff --git a/src/rtextures.c b/src/rtextures.c index e860df100..b33ab5c50 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -70,6 +70,7 @@ #include // Required for: strlen() [Used in ImageTextEx()], strcmp() [Used in LoadImageFromMemory()/LoadImageAnimFromMemory()/ExportImageToMemory()] #include // Required for: fabsf() [Used in DrawTextureRec()] #include // Required for: sprintf() [Used in ExportImageAsCode()] +#include // Required for: INT_MAX // Support only desired texture formats on stb_image #if !SUPPORT_FILEFORMAT_BMP From fb4649a3feeb35c66333a4c4f0a8c3f1cbc4a3b2 Mon Sep 17 00:00:00 2001 From: Luis <113704180+LuisR385@users.noreply.github.com> Date: Mon, 13 Jul 2026 22:10:27 +0900 Subject: [PATCH 54/94] [rcore][desktop] Fix clipboard image memory leak (#5968) * [rcore][desktop] Fix clipboard image memory leak * [delete] delete comment GetClipboardImage into NOTE about where put SDL_free() . --- src/platforms/rcore_desktop_sdl.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index f51eedd97..0936dda0e 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -1255,12 +1255,14 @@ Image GetClipboardImage(void) for (int i = 0; i < SDL_arraysize(imageFormats); i++) { - // NOTE: This pointer should be free with SDL_free() at some point fileData = SDL_GetClipboardData(imageFormats[i], &dataSize); if (fileData) { image = LoadImageFromMemory(imageExtensions[i], fileData, (int)dataSize); + + SDL_free(fileData); + if (IsImageValid(image)) { TRACELOG(LOG_INFO, "Clipboard: Got image from clipboard successfully: %s", imageExtensions[i]); From b631fb3d052b767ccd0281b0d008cdaf810b5267 Mon Sep 17 00:00:00 2001 From: Thiago Mucci Date: Mon, 13 Jul 2026 09:11:42 -0400 Subject: [PATCH 55/94] Fix TextSubtext() returning empty string when position is 0 (#5975) --- src/rtext.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rtext.c b/src/rtext.c index 35c6f7307..248857975 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -1699,7 +1699,7 @@ const char *TextSubtext(const char *text, int position, int length) static char buffer[MAX_TEXT_BUFFER_LENGTH] = { 0 }; memset(buffer, 0, MAX_TEXT_BUFFER_LENGTH); - if ((text != NULL) && (position > 0) && (length > 0)) + if ((text != NULL) && (position >= 0) && (length > 0)) { int textLength = TextLength(text); From 5de8c3521fc909e7f1baa5573329dfe7019e6ab7 Mon Sep 17 00:00:00 2001 From: Commmand_Prompt <62493399+CommandPrompt-Wang@users.noreply.github.com> Date: Mon, 13 Jul 2026 21:13:12 +0800 Subject: [PATCH 56/94] fix: ImageFromImage rectangle validation use >= and <= (#5979) --- src/rtextures.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/rtextures.c b/src/rtextures.c index b33ab5c50..850161548 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -1231,9 +1231,9 @@ Image ImageFromImage(Image image, Rectangle rec) Image result = { 0 }; // Basic rectangle validation: size smaller than image size - if ((rec.x > 0) && (rec.y > 0) && (rec.width > 0) && (rec.height > 0) && - (((int)rec.x + (int)rec.width) < image.width) && - (((int)rec.y + (int)rec.height) < image.height)) + if ((rec.x >= 0) && (rec.y >= 0) && (rec.width > 0) && (rec.height > 0) && + (((int)rec.x + (int)rec.width) <= image.width) && + (((int)rec.y + (int)rec.height) <= image.height)) { int bytesPerPixel = GetPixelDataSize(1, 1, image.format); From 7a247ff40fc5e77243b6e0af856437d2e6231c31 Mon Sep 17 00:00:00 2001 From: Thiago Mucci Date: Mon, 13 Jul 2026 13:19:02 -0400 Subject: [PATCH 57/94] Fix swScissor() Y-axis clipping inversion in software renderer (#5976) --- src/external/rlsw.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/external/rlsw.h b/src/external/rlsw.h index bb6e11679..6ca1cecf1 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -4307,8 +4307,8 @@ void swScissor(int x, int y, int width, int height) RLSW.scClipMin[0] = (2.0f*(float)RLSW.scMin[0]/(float)RLSW.vpSize[0]) - 1.0f; RLSW.scClipMax[0] = (2.0f*(float)RLSW.scMax[0]/(float)RLSW.vpSize[0]) - 1.0f; - RLSW.scClipMax[1] = 1.0f - (2.0f*(float)RLSW.scMin[1]/(float)RLSW.vpSize[1]); - RLSW.scClipMin[1] = 1.0f - (2.0f*(float)RLSW.scMax[1]/(float)RLSW.vpSize[1]); + RLSW.scClipMin[1] = (2.0f*(float)RLSW.scMin[1]/(float)RLSW.vpSize[1]) - 1.0f; + RLSW.scClipMax[1] = (2.0f*(float)RLSW.scMax[1]/(float)RLSW.vpSize[1]) - 1.0f; } void swClearColor(float r, float g, float b, float a) From e063385c477b0320ea8836f10acd70cc52d778e4 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 13 Jul 2026 19:24:49 +0200 Subject: [PATCH 58/94] Fix #5965 --- examples/shaders/resources/shaders/glsl100/pbr.fs | 2 +- examples/shaders/resources/shaders/glsl120/pbr.fs | 2 +- examples/shaders/resources/shaders/glsl330/pbr.fs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/shaders/resources/shaders/glsl100/pbr.fs b/examples/shaders/resources/shaders/glsl100/pbr.fs index 28212bf63..f29cb0e59 100644 --- a/examples/shaders/resources/shaders/glsl100/pbr.fs +++ b/examples/shaders/resources/shaders/glsl100/pbr.fs @@ -99,7 +99,7 @@ vec3 ComputePBR() vec3 N = normalize(fragNormal); if (useTexNormal == 1) { - N = texture2D(normalMap, vec2(fragTexCoord.x*tiling.x + offset.y, fragTexCoord.y*tiling.y + offset.y)).rgb; + N = texture2D(normalMap, vec2(fragTexCoord.x*tiling.x + offset.x, fragTexCoord.y*tiling.y + offset.y)).rgb; N = normalize(N*2.0 - 1.0); N = normalize(N*TBN); } diff --git a/examples/shaders/resources/shaders/glsl120/pbr.fs b/examples/shaders/resources/shaders/glsl120/pbr.fs index b36b76bee..450986f1b 100644 --- a/examples/shaders/resources/shaders/glsl120/pbr.fs +++ b/examples/shaders/resources/shaders/glsl120/pbr.fs @@ -97,7 +97,7 @@ vec3 ComputePBR() vec3 N = normalize(fragNormal); if (useTexNormal == 1) { - N = texture2D(normalMap, vec2(fragTexCoord.x*tiling.x + offset.y, fragTexCoord.y*tiling.y + offset.y)).rgb; + N = texture2D(normalMap, vec2(fragTexCoord.x*tiling.x + offset.x, fragTexCoord.y*tiling.y + offset.y)).rgb; N = normalize(N*2.0 - 1.0); N = normalize(N*TBN); } diff --git a/examples/shaders/resources/shaders/glsl330/pbr.fs b/examples/shaders/resources/shaders/glsl330/pbr.fs index ceaead308..67254851c 100644 --- a/examples/shaders/resources/shaders/glsl330/pbr.fs +++ b/examples/shaders/resources/shaders/glsl330/pbr.fs @@ -100,7 +100,7 @@ vec3 ComputePBR() vec3 N = normalize(fragNormal); if (useTexNormal == 1) { - N = texture(normalMap, vec2(fragTexCoord.x*tiling.x + offset.y, fragTexCoord.y*tiling.y + offset.y)).rgb; + N = texture(normalMap, vec2(fragTexCoord.x*tiling.x + offset.x, fragTexCoord.y*tiling.y + offset.y)).rgb; N = normalize(N*2.0 - 1.0); N = normalize(N*TBN); } From 4640c849208079d758d8f0dbb4b5b7816db5ed0c Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 13 Jul 2026 19:32:30 +0200 Subject: [PATCH 59/94] WARNING: Not updating mouse.previousPosition when `SeMousePosition()` #5962 This could be a sensible change, not sure if it can break anything... --- src/platforms/rcore_android.c | 1 - src/platforms/rcore_desktop_glfw.c | 1 - src/platforms/rcore_desktop_rgfw.c | 1 - src/platforms/rcore_desktop_sdl.c | 1 - src/platforms/rcore_desktop_win32.c | 4 ++-- src/platforms/rcore_drm.c | 1 - src/platforms/rcore_memory.c | 1 - src/platforms/rcore_template.c | 1 - src/platforms/rcore_web.c | 1 - 9 files changed, 2 insertions(+), 10 deletions(-) diff --git a/src/platforms/rcore_android.c b/src/platforms/rcore_android.c index f88f53c4c..7fb080153 100644 --- a/src/platforms/rcore_android.c +++ b/src/platforms/rcore_android.c @@ -726,7 +726,6 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d void SetMousePosition(int x, int y) { CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y }; - CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; } // Set mouse cursor diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index f1bf0ae8e..40da5b804 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -1237,7 +1237,6 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d void SetMousePosition(int x, int y) { CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y }; - CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; // NOTE: emscripten not implemented glfwSetCursorPos(platform.handle, CORE.Input.Mouse.currentPosition.x, CORE.Input.Mouse.currentPosition.y); diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index 814eda553..9907e8a60 100644 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -1526,7 +1526,6 @@ void SetMousePosition(int x, int y) { RGFW_window_moveMouse(platform.window, x, y); CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y }; - CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; } // Set mouse cursor diff --git a/src/platforms/rcore_desktop_sdl.c b/src/platforms/rcore_desktop_sdl.c index 0936dda0e..bca579e41 100644 --- a/src/platforms/rcore_desktop_sdl.c +++ b/src/platforms/rcore_desktop_sdl.c @@ -1411,7 +1411,6 @@ void SetMousePosition(int x, int y) SDL_WarpMouseInWindow(platform.window, x, y); CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y }; - CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; } // Set mouse cursor diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c index 00d5565e2..a6e85a657 100644 --- a/src/platforms/rcore_desktop_win32.c +++ b/src/platforms/rcore_desktop_win32.c @@ -1299,8 +1299,8 @@ void SetMousePosition(int x, int y) if (!CORE.Input.Mouse.cursorLocked) { CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y }; - CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; - TRACELOG(LOG_WARNING, "SetMousePosition not implemented"); + + TRACELOG(LOG_WARNING, "SetMousePosition not implemented at platform level"); } else TRACELOG(LOG_WARNING, "INPUT: MOUSE: Cursor not enabled"); } diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c index 662b52373..4d4a4d3bf 100644 --- a/src/platforms/rcore_drm.c +++ b/src/platforms/rcore_drm.c @@ -1042,7 +1042,6 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d void SetMousePosition(int x, int y) { CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y }; - CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; } // Set mouse cursor diff --git a/src/platforms/rcore_memory.c b/src/platforms/rcore_memory.c index 14c56a591..03b787da6 100644 --- a/src/platforms/rcore_memory.c +++ b/src/platforms/rcore_memory.c @@ -420,7 +420,6 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d void SetMousePosition(int x, int y) { CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y }; - CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; } // Set mouse cursor diff --git a/src/platforms/rcore_template.c b/src/platforms/rcore_template.c index 216c49af8..1866059e8 100644 --- a/src/platforms/rcore_template.c +++ b/src/platforms/rcore_template.c @@ -395,7 +395,6 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d void SetMousePosition(int x, int y) { CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y }; - CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; } // Set mouse cursor diff --git a/src/platforms/rcore_web.c b/src/platforms/rcore_web.c index dcc83accf..b95121d2c 100644 --- a/src/platforms/rcore_web.c +++ b/src/platforms/rcore_web.c @@ -1047,7 +1047,6 @@ void SetGamepadVibration(int gamepad, float leftMotor, float rightMotor, float d void SetMousePosition(int x, int y) { CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y }; - CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition; if (CORE.Input.Mouse.cursorLocked) CORE.Input.Mouse.lockedPosition = CORE.Input.Mouse.currentPosition; From 39706cccbe3691a635e5210b4bd315d88856d54d Mon Sep 17 00:00:00 2001 From: Samael Heaven <126531890+SamaelHeaven@users.noreply.github.com> Date: Wed, 15 Jul 2026 15:20:18 -0400 Subject: [PATCH 60/94] [rshapes] Fix DrawRectangleRoundedLinesEx not scaling with transform when thick=1 (#5980) --- src/rshapes.c | 300 ++++++++++++++++++++++---------------------------- 1 file changed, 134 insertions(+), 166 deletions(-) diff --git a/src/rshapes.c b/src/rshapes.c index 12ae6a164..def6d36b2 100644 --- a/src/rshapes.c +++ b/src/rshapes.c @@ -888,14 +888,13 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co // Draw rectangle with rounded edges void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, Color color) { - // NOTE: For line thicknes <=1.0f using RL_LINES, otherwise using RL_QUADS/RL_TRIANGLES DrawRectangleRoundedLinesEx(rec, roundness, segments, 1.0f, color); } // Draw rectangle with rounded edges outline with line thickness void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, float thick, Color color) { - if (thick < 0) thick = 0; + if (thick <= 0) return; // Not a rounded rectangle if (roundness <= 0.0f) @@ -966,176 +965,145 @@ void DrawRectangleRoundedLinesEx(Rectangle rec, float roundness, int segments, f const float angles[4] = { 180.0f, 270.0f, 0.0f, 90.0f }; - if (thick > 1) - { #if SUPPORT_QUADS_DRAW_MODE - rlSetTexture(GetShapesTexture().id); - Rectangle shapeRect = GetShapesTextureRectangle(); + rlSetTexture(GetShapesTexture().id); + Rectangle shapeRect = GetShapesTextureRectangle(); - rlBegin(RL_QUADS); + rlBegin(RL_QUADS); - // Draw all the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner - for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop - { - float angle = angles[k]; - const Vector2 center = centers[k]; - for (int i = 0; i < segments; i++) - { - rlColor4ub(color.r, color.g, color.b, color.a); - - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius); - - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius); - - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius); - - angle += stepLength; - } - } - - // Upper rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[0].x, point[0].y); - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[8].x, point[8].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[9].x, point[9].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[1].x, point[1].y); - - // Right rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[2].x, point[2].y); - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[10].x, point[10].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[11].x, point[11].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[3].x, point[3].y); - - // Lower rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[13].x, point[13].y); - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[5].x, point[5].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[4].x, point[4].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[12].x, point[12].y); - - // Left rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[15].x, point[15].y); - rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[7].x, point[7].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); - rlVertex2f(point[6].x, point[6].y); - rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); - rlVertex2f(point[14].x, point[14].y); - - rlEnd(); - rlSetTexture(0); -#else - rlBegin(RL_TRIANGLES); - - // Draw all of the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner - for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop - { - float angle = angles[k]; - const Vector2 center = centers[k]; - - for (int i = 0; i < segments; i++) - { - rlColor4ub(color.r, color.g, color.b, color.a); - - rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius); - - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius); - - angle += stepLength; - } - } - - // Upper rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(point[0].x, point[0].y); - rlVertex2f(point[8].x, point[8].y); - rlVertex2f(point[9].x, point[9].y); - rlVertex2f(point[1].x, point[1].y); - rlVertex2f(point[0].x, point[0].y); - rlVertex2f(point[9].x, point[9].y); - - // Right rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(point[10].x, point[10].y); - rlVertex2f(point[11].x, point[11].y); - rlVertex2f(point[3].x, point[3].y); - rlVertex2f(point[2].x, point[2].y); - rlVertex2f(point[10].x, point[10].y); - rlVertex2f(point[3].x, point[3].y); - - // Lower rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(point[13].x, point[13].y); - rlVertex2f(point[5].x, point[5].y); - rlVertex2f(point[4].x, point[4].y); - rlVertex2f(point[12].x, point[12].y); - rlVertex2f(point[13].x, point[13].y); - rlVertex2f(point[4].x, point[4].y); - - // Left rectangle - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(point[7].x, point[7].y); - rlVertex2f(point[6].x, point[6].y); - rlVertex2f(point[14].x, point[14].y); - rlVertex2f(point[15].x, point[15].y); - rlVertex2f(point[7].x, point[7].y); - rlVertex2f(point[14].x, point[14].y); - rlEnd(); -#endif - } - else - { - // Use LINES to draw the outline - rlBegin(RL_LINES); - // Draw all the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner - for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop - { - float angle = angles[k]; - const Vector2 center = centers[k]; - - for (int i = 0; i < segments; i++) - { - rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius); - rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius); - angle += stepLength; - } - } - - // And now the remaining 4 lines - for (int i = 0; i < 8; i += 2) + // Draw all the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner + for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop + { + float angle = angles[k]; + const Vector2 center = centers[k]; + for (int i = 0; i < segments; i++) { rlColor4ub(color.r, color.g, color.b, color.a); - rlVertex2f(point[i].x, point[i].y); - rlVertex2f(point[i + 1].x, point[i + 1].y); + + rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); + rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius); + + rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); + rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius); + + rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); + rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius); + + rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); + rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius); + + angle += stepLength; } - rlEnd(); - } + } + + // Upper rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); + rlVertex2f(point[0].x, point[0].y); + rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); + rlVertex2f(point[8].x, point[8].y); + rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); + rlVertex2f(point[9].x, point[9].y); + rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); + rlVertex2f(point[1].x, point[1].y); + + // Right rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); + rlVertex2f(point[2].x, point[2].y); + rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); + rlVertex2f(point[10].x, point[10].y); + rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); + rlVertex2f(point[11].x, point[11].y); + rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); + rlVertex2f(point[3].x, point[3].y); + + // Lower rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); + rlVertex2f(point[13].x, point[13].y); + rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); + rlVertex2f(point[5].x, point[5].y); + rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); + rlVertex2f(point[4].x, point[4].y); + rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); + rlVertex2f(point[12].x, point[12].y); + + // Left rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlTexCoord2f(shapeRect.x/texShapes.width, shapeRect.y/texShapes.height); + rlVertex2f(point[15].x, point[15].y); + rlTexCoord2f(shapeRect.x/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); + rlVertex2f(point[7].x, point[7].y); + rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, (shapeRect.y + shapeRect.height)/texShapes.height); + rlVertex2f(point[6].x, point[6].y); + rlTexCoord2f((shapeRect.x + shapeRect.width)/texShapes.width, shapeRect.y/texShapes.height); + rlVertex2f(point[14].x, point[14].y); + + rlEnd(); + rlSetTexture(0); +#else + rlBegin(RL_TRIANGLES); + + // Draw all of the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner + for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop + { + float angle = angles[k]; + const Vector2 center = centers[k]; + + for (int i = 0; i < segments; i++) + { + rlColor4ub(color.r, color.g, color.b, color.a); + + rlVertex2f(center.x + cosf(DEG2RAD*angle)*innerRadius, center.y + sinf(DEG2RAD*angle)*innerRadius); + rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius); + rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius); + + rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*innerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*innerRadius); + rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*outerRadius, center.y + sinf(DEG2RAD*(angle + stepLength))*outerRadius); + rlVertex2f(center.x + cosf(DEG2RAD*angle)*outerRadius, center.y + sinf(DEG2RAD*angle)*outerRadius); + + angle += stepLength; + } + } + + // Upper rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(point[0].x, point[0].y); + rlVertex2f(point[8].x, point[8].y); + rlVertex2f(point[9].x, point[9].y); + rlVertex2f(point[1].x, point[1].y); + rlVertex2f(point[0].x, point[0].y); + rlVertex2f(point[9].x, point[9].y); + + // Right rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(point[10].x, point[10].y); + rlVertex2f(point[11].x, point[11].y); + rlVertex2f(point[3].x, point[3].y); + rlVertex2f(point[2].x, point[2].y); + rlVertex2f(point[10].x, point[10].y); + rlVertex2f(point[3].x, point[3].y); + + // Lower rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(point[13].x, point[13].y); + rlVertex2f(point[5].x, point[5].y); + rlVertex2f(point[4].x, point[4].y); + rlVertex2f(point[12].x, point[12].y); + rlVertex2f(point[13].x, point[13].y); + rlVertex2f(point[4].x, point[4].y); + + // Left rectangle + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(point[7].x, point[7].y); + rlVertex2f(point[6].x, point[6].y); + rlVertex2f(point[14].x, point[14].y); + rlVertex2f(point[15].x, point[15].y); + rlVertex2f(point[7].x, point[7].y); + rlVertex2f(point[14].x, point[14].y); + rlEnd(); +#endif } // Draw a polygon of n sides From d224912bd5fa1a1c2ed83ae704a31337060aabab Mon Sep 17 00:00:00 2001 From: Tanushn <139579436+iztanos@users.noreply.github.com> Date: Thu, 16 Jul 2026 00:51:38 +0530 Subject: [PATCH 61/94] Fix rlsw persistent alpha blending state (#5964) --- src/external/rlsw.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/external/rlsw.h b/src/external/rlsw.h index 6ca1cecf1..db10bf2b4 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -3909,7 +3909,6 @@ static void sw_immediate_set_color(const float color[4]) RLSW.primitive.color[2] = color[2]; RLSW.primitive.color[3] = color[3]; - RLSW.primitive.hasColorAlpha |= (color[3] < 1.0f); } static void sw_immediate_set_texcoord(const float texcoord[2]) @@ -3948,6 +3947,9 @@ static void sw_immediate_push_vertex(const float position[4]) for (int i = 0; i < 4; i++) vertex->color[i] = RLSW.primitive.color[i]; for (int i = 0; i < 2; i++) vertex->texcoord[i] = RLSW.primitive.texcoord[i]; + // Track whether any vertex in this primitive has alpha < 1.0 + RLSW.primitive.hasColorAlpha |= (vertex->color[3] < 1.0f); + // Immediate rendering of the primitive if the required number is reached if (RLSW.primitive.vertexCount == SW_PRIMITIVE_VERTEX_COUNT[RLSW.drawMode]) { From a9a0c046f1f8850de1f5d51f7b5d44895fd46b4c Mon Sep 17 00:00:00 2001 From: GideonSerf Date: Thu, 16 Jul 2026 12:07:19 +0200 Subject: [PATCH 62/94] Fix pixel data size regressions (#5984) Co-authored-by: gideons --- src/rlgl.h | 8 ++++---- src/rtextures.c | 7 ++++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/rlgl.h b/src/rlgl.h index 3d4a54d6f..68eec7fdf 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -5237,7 +5237,7 @@ static int rlGetPixelDataSize(int width, int height, int format) { int blockWidth = (width + 3)/4; int blockHeight = (height + 3)/4; - unsigned long long dataSizeBytes = blockWidth*blockHeight*8; + unsigned long long dataSizeBytes = (unsigned long long)blockWidth*blockHeight*8; if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes; } break; @@ -5248,7 +5248,7 @@ static int rlGetPixelDataSize(int width, int height, int format) { int blockWidth = (width + 3)/4; int blockHeight = (height + 3)/4; - unsigned long long dataSizeBytes = blockWidth*blockHeight*16; + unsigned long long dataSizeBytes = (unsigned long long)blockWidth*blockHeight*16; if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes; } break; @@ -5256,7 +5256,7 @@ static int rlGetPixelDataSize(int width, int height, int format) { int blockWidth = (width + 3)/4; int blockHeight = (height + 3)/4; - unsigned long long dataSizeBytes = blockWidth*blockHeight*4; + unsigned long long dataSizeBytes = (unsigned long long)blockWidth*blockHeight*4; if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes; } break; @@ -5267,7 +5267,7 @@ static int rlGetPixelDataSize(int width, int height, int format) if ((format >= RL_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE) && (format <= RL_PIXELFORMAT_UNCOMPRESSED_R16G16B16A16)) { - unsigned long long dataSizeBytes = (width*height*bpp) >> 3; // Get size in bytes (dividing by 8) + unsigned long long dataSizeBytes = ((unsigned long long)width*height*bpp) >> 3; // Get size in bytes (dividing by 8) if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes; } diff --git a/src/rtextures.c b/src/rtextures.c index 850161548..61e528d47 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -2693,8 +2693,9 @@ void ImageRotate(Image *image, int degrees) int width = (int)(fabsf(image->width*cosRadius) + fabsf(image->height*sinRadius)); int height = (int)(fabsf(image->height*cosRadius) + fabsf(image->width*sinRadius)); - int bytesPerPixel = GetPixelDataSize(width, height, image->format); - unsigned char *rotatedData = (unsigned char *)RL_CALLOC(bytesPerPixel, 1); + int dataSize = GetPixelDataSize(width, height, image->format); + int bytesPerPixel = GetPixelDataSize(1, 1, image->format); + unsigned char *rotatedData = (unsigned char *)RL_CALLOC(dataSize, 1); if (rotatedData != NULL) { @@ -5514,7 +5515,7 @@ int GetPixelDataSize(int width, int height, int format) default: break; } - unsigned long long dataSizeBytes = (width*height*bpp) >> 3; // Get size in bytes (dividing by 8) + unsigned long long dataSizeBytes = ((unsigned long long)width*height*bpp) >> 3; // Get size in bytes (dividing by 8) if (dataSizeBytes < INT_MAX) { From 93e64f2210be64250641b94ab259d85b53ba8639 Mon Sep 17 00:00:00 2001 From: GideonSerf Date: Thu, 16 Jul 2026 12:08:41 +0200 Subject: [PATCH 63/94] Fix TextInsertAlloc overflow by correcting loop bounds (#5982) Co-authored-by: gideons --- src/rtext.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rtext.c b/src/rtext.c index 248857975..0431a6f57 100644 --- a/src/rtext.c +++ b/src/rtext.c @@ -2014,7 +2014,7 @@ char *TextInsertAlloc(const char *text, const char *insert, int position) for (int i = 0; i < position; i++) result[i] = text[i]; for (int i = position; i < (insertLen + position); i++) result[i] = insert[i - position]; - for (int i = (insertLen + position); i < (textLen + insertLen + position); i++) result[i] = text[i - insertLen]; + for (int i = (insertLen + position); i < (textLen + insertLen); i++) result[i] = text[i - insertLen]; result[textLen + insertLen] = '\0'; // Add EOL } From 89b4fbd29854c6c4b5472d8d1417450b8f65bd5c Mon Sep 17 00:00:00 2001 From: largenumberhere <60594766+largenumberhere@users.noreply.github.com> Date: Thu, 16 Jul 2026 20:10:03 +1000 Subject: [PATCH 64/94] [rcore] fic position on mouse leave for emscripten. Issue raysan5#5945 followup (#5981) --- src/platforms/rcore_web_emscripten.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/platforms/rcore_web_emscripten.c b/src/platforms/rcore_web_emscripten.c index ff10fabb3..fa967057a 100644 --- a/src/platforms/rcore_web_emscripten.c +++ b/src/platforms/rcore_web_emscripten.c @@ -1507,8 +1507,16 @@ static EM_BOOL EmscriptenMouseCallback(int eventType, const EmscriptenMouseEvent { switch (eventType) { - case EMSCRIPTEN_EVENT_MOUSEENTER: CORE.Input.Mouse.cursorOnScreen = true; break; - case EMSCRIPTEN_EVENT_MOUSELEAVE: CORE.Input.Mouse.cursorOnScreen = false; break; + case EMSCRIPTEN_EVENT_MOUSEENTER: { + // NOTE: Mouse position updated by EmscriptenMouseMoveCallback(), + // EmscriptenPointerlockCallback(), and EmscriptenTouchCallback() + CORE.Input.Mouse.cursorOnScreen = true; + } break; + case EMSCRIPTEN_EVENT_MOUSELEAVE: + { + CORE.Input.Mouse.cursorOnScreen = false; + CORE.Input.Mouse.currentPosition = (Vector2){ 0 }; + } break; case EMSCRIPTEN_EVENT_MOUSEDOWN: { // NOTE: Emscripten and raylib buttons indices are not aligned From 8eb613e50a95906d7bf9b19c895894bbdee8b5fb Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 16 Jul 2026 12:28:25 +0200 Subject: [PATCH 65/94] Update rcore_desktop_glfw.c --- src/platforms/rcore_desktop_glfw.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index 40da5b804..934815c0f 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -1325,7 +1325,7 @@ void PollInputEvents(void) // Register previous gamepad states for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k]; - // Get current gamepad state + // Get current gamepad state using internal GLFW mapping, instead of the immediate joystick API // NOTE: There is no callback available, getting it manually GLFWgamepadstate state = { 0 }; int result = glfwGetGamepadState(i, &state); // This remaps all gamepads so they have their buttons mapped like an xbox controller @@ -1340,7 +1340,7 @@ void PollInputEvents(void) for (int k = 0; (buttons != NULL) && (k < MAX_GAMEPAD_BUTTONS); k++) { - int button = -1; // GamepadButton enum values assigned + int button = -1; // GamepadButton enum values assigned switch (k) { @@ -1366,7 +1366,7 @@ void PollInputEvents(void) default: break; } - if (button != -1) // Check for valid button + if (button != -1) // Check for valid button { if (buttons[k] == GLFW_PRESS) { @@ -1408,10 +1408,10 @@ void PollInputEvents(void) if ((CORE.Window.eventWaiting) || (FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_MINIMIZED) && !FLAG_IS_SET(CORE.Window.flags, FLAG_WINDOW_ALWAYS_RUN))) { - glfwWaitEvents(); // Wait for in input events before continue (drawing is paused) + glfwWaitEvents(); // Wait for in input events before continue (drawing is paused) CORE.Time.previous = GetTime(); } - else glfwPollEvents(); // Poll input events: keyboard/mouse/window events (callbacks) -> Update keys state + else glfwPollEvents(); // Poll input events: keyboard/mouse/window events (callbacks) -> Update keys state CORE.Window.shouldClose = glfwWindowShouldClose(platform.handle); From 62a74a342c55858c1390eed0075ea9780b4e9272 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 16 Jul 2026 15:05:32 +0200 Subject: [PATCH 66/94] Update README.md --- projects/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/projects/README.md b/projects/README.md index 2758cb86e..27196b93a 100644 --- a/projects/README.md +++ b/projects/README.md @@ -9,10 +9,10 @@ IDE | Platform(s) | Source | Example(s) [CMake](https://cmake.org/) | Windows, Linux, macOS, Web | ✔️ | ✔️ [CodeBlocks](http://www.codeblocks.org/) | Windows, Linux, macOS | ❌ | ✔️ [Geany](https://www.geany.org/) | Windows, Linux | ✔️ | ✔️ -[Notepad++](https://notepad-plus-plus.org/) | Windows | ✔️ | ✔️ +[Notepad++](https://notepad-plus-plus.org/) | Windows, Web | ✔️ | ✔️ [SublimeText](https://www.sublimetext.com/) | Windows, Linux, macOS | ✔️ | ✔️ -[VS2019](https://www.visualstudio.com) | Windows | ✔️ | ✔️ -[VSCode](https://code.visualstudio.com/) | Windows, macOS | ❌ | ✔️ +[VS2022](https://www.visualstudio.com) | Windows | ✔️ | ✔️ +[VSCode](https://code.visualstudio.com/) | Windows, Linux, macOS | ❌ | ✔️ [Zig](https://ziglang.org) | Windows, Linux, macOS, Web | ✔️ | ✔️ scripts | Windows, Linux, macOS | ✔️ | ✔️ From 742ccb390af158b0c758e814cc567227134bb3b2 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 16 Jul 2026 15:08:12 +0200 Subject: [PATCH 67/94] REMOVED: Unmaintained project: 4coder --- projects/4coder/Makefile | 401 ------------------------------- projects/4coder/Makefile.Android | 300 ----------------------- projects/4coder/main.c | 40 --- projects/4coder/project.4coder | 54 ----- 4 files changed, 795 deletions(-) delete mode 100644 projects/4coder/Makefile delete mode 100644 projects/4coder/Makefile.Android delete mode 100644 projects/4coder/main.c delete mode 100644 projects/4coder/project.4coder diff --git a/projects/4coder/Makefile b/projects/4coder/Makefile deleted file mode 100644 index ec0977aaf..000000000 --- a/projects/4coder/Makefile +++ /dev/null @@ -1,401 +0,0 @@ -#************************************************************************************************** -# -# raylib makefile for Desktop platforms, Raspberry Pi, Android and HTML5 -# -# Copyright (c) 2013-2026 Ramon Santamaria (@raysan5) -# -# This software is provided "as-is", without any express or implied warranty. In no event -# will the authors be held liable for any damages arising from the use of this software. -# -# Permission is granted to anyone to use this software for any purpose, including commercial -# applications, and to alter it and redistribute it freely, subject to the following restrictions: -# -# 1. The origin of this software must not be misrepresented; you must not claim that you -# wrote the original software. If you use this software in a product, an acknowledgment -# in the product documentation would be appreciated but is not required. -# -# 2. Altered source versions must be plainly marked as such, and must not be misrepresented -# as being the original software. -# -# 3. This notice may not be removed or altered from any source distribution. -# -#************************************************************************************************** - -.PHONY: all clean - -# Define required raylib variables -PROJECT_NAME ?= game -RAYLIB_VERSION ?= 4.2.0 -RAYLIB_PATH ?= ..\.. - -# Define default options - -# One of PLATFORM_DESKTOP, PLATFORM_RPI, PLATFORM_ANDROID, PLATFORM_WEB -PLATFORM ?= PLATFORM_DESKTOP - -# Locations of your newly installed library and associated headers. See ../src/Makefile -# On Linux, if you have installed raylib but cannot compile the examples, check that -# the *_INSTALL_PATH values here are the same as those in src/Makefile or point to known locations. -# To enable system-wide compile-time and runtime linking to libraylib.so, run ../src/$ sudo make install RAYLIB_LIBTYPE_SHARED. -# To enable compile-time linking to a special version of libraylib.so, change these variables here. -# To enable runtime linking to a special version of libraylib.so, see EXAMPLE_RUNTIME_PATH below. -# If there is a libraylib in both EXAMPLE_RUNTIME_PATH and RAYLIB_INSTALL_PATH, at runtime, -# the library at EXAMPLE_RUNTIME_PATH, if present, will take precedence over the one at RAYLIB_INSTALL_PATH. -# RAYLIB_INSTALL_PATH should be the desired full path to libraylib. No relative paths. -DESTDIR ?= /usr/local -RAYLIB_INSTALL_PATH ?= $(DESTDIR)/lib -# RAYLIB_H_INSTALL_PATH locates the installed raylib header and associated source files. -RAYLIB_H_INSTALL_PATH ?= $(DESTDIR)/include - -# Library type used for raylib: STATIC (.a) or SHARED (.so/.dll) -RAYLIB_LIBTYPE ?= STATIC - -# Build mode for project: DEBUG or RELEASE -BUILD_MODE ?= RELEASE - -# Use external GLFW library instead of rglfw module -# TODO: Review usage on Linux. Target version of choice. Switch on -lglfw or -lglfw3 -USE_EXTERNAL_GLFW ?= FALSE - -# Use Wayland display server protocol on Linux desktop -# by default it uses X11 windowing system -USE_WAYLAND_DISPLAY ?= FALSE - -# Determine PLATFORM_OS in case PLATFORM_DESKTOP selected -ifeq ($(PLATFORM),PLATFORM_DESKTOP) - # No uname.exe on MinGW!, but OS=Windows_NT on Windows! - # ifeq ($(UNAME),Msys) -> Windows - ifeq ($(OS),Windows_NT) - PLATFORM_OS=WINDOWS - else - UNAMEOS=$(shell uname) - ifeq ($(UNAMEOS),Linux) - PLATFORM_OS=LINUX - endif - ifeq ($(UNAMEOS),FreeBSD) - PLATFORM_OS=BSD - endif - ifeq ($(UNAMEOS),OpenBSD) - PLATFORM_OS=BSD - endif - ifeq ($(UNAMEOS),NetBSD) - PLATFORM_OS=BSD - endif - ifeq ($(UNAMEOS),DragonFly) - PLATFORM_OS=BSD - endif - ifeq ($(UNAMEOS),Darwin) - PLATFORM_OS=OSX - endif - endif -endif -ifeq ($(PLATFORM),PLATFORM_RPI) - UNAMEOS=$(shell uname) - ifeq ($(UNAMEOS),Linux) - PLATFORM_OS=LINUX - endif -endif - -# RAYLIB_PATH adjustment for different platforms. -# If using GNU make, we can get the full path to the top of the tree. Windows? BSD? -# Required for ldconfig or other tools that do not perform path expansion. -ifeq ($(PLATFORM),PLATFORM_DESKTOP) - ifeq ($(PLATFORM_OS),LINUX) - RAYLIB_PREFIX ?= .. - RAYLIB_PATH = $(realpath $(RAYLIB_PREFIX)) - endif -endif -# Default path for raylib on Raspberry Pi, if installed in different path, update it! -# This is not currently used by src/Makefile. Not sure of its origin or usage. Refer to wiki. -# TODO: update install: target in src/Makefile for RPI, consider relation to LINUX. -ifeq ($(PLATFORM),PLATFORM_RPI) - RAYLIB_PATH ?= /home/pi/raylib -endif - -ifeq ($(PLATFORM),PLATFORM_WEB) - # Emscripten required variables - EMSDK_PATH ?= C:/raylib/emsdk - EMSCRIPTEN_PATH ?= $(EMSDK_PATH)/upstream/emscripten - CLANG_PATH = $(EMSDK_PATH)/upstream/bin - PYTHON_PATH = $(EMSDK_PATH)/python/3.13.3_64bit - NODE_PATH = $(EMSDK_PATH)/node/22.16.0_64bit/bin - export PATH = $(EMSDK_PATH);$(EMSCRIPTEN_PATH);$(CLANG_PATH);$(NODE_PATH);$(PYTHON_PATH);C:\raylib\MinGW\bin:$$(PATH) -endif - -# Define raylib release directory for compiled library. -# RAYLIB_RELEASE_PATH points to provided binaries or your freshly built version -RAYLIB_RELEASE_PATH ?= $(RAYLIB_PATH)/src - -# EXAMPLE_RUNTIME_PATH embeds a custom runtime location of libraylib.so or other desired libraries -# into each example binary compiled with RAYLIB_LIBTYPE=SHARED. It defaults to RAYLIB_RELEASE_PATH -# so that these examples link at runtime with your version of libraylib.so in ../release/libs/linux -# without formal installation from ../src/Makefile. It aids portability and is useful if you have -# multiple versions of raylib, have raylib installed to a non-standard location, or want to -# bundle libraylib.so with your game. Change it to your liking. -# NOTE: If, at runtime, there is a libraylib.so at both EXAMPLE_RUNTIME_PATH and RAYLIB_INSTALL_PATH, -# The library at EXAMPLE_RUNTIME_PATH, if present, will take precedence over RAYLIB_INSTALL_PATH, -# Implemented for LINUX below with CFLAGS += -Wl,-rpath,$(EXAMPLE_RUNTIME_PATH) -# To see the result, run readelf -d core/core_basic_window; looking at the RPATH or RUNPATH attribute. -# To see which libraries a built example is linking to, ldd core/core_basic_window; -# Look for libraylib.so.1 => $(RAYLIB_INSTALL_PATH)/libraylib.so.1 or similar listing. -EXAMPLE_RUNTIME_PATH ?= $(RAYLIB_RELEASE_PATH) - -# Define default C compiler: gcc -# NOTE: define g++ compiler if using C++ -CC = gcc - -ifeq ($(PLATFORM),PLATFORM_DESKTOP) - ifeq ($(PLATFORM_OS),OSX) - # OSX default compiler - CC = clang - endif - ifeq ($(PLATFORM_OS),BSD) - # FreeBSD, OpenBSD, NetBSD, DragonFly default compiler - CC = clang - endif -endif -ifeq ($(PLATFORM),PLATFORM_RPI) - ifeq ($(USE_RPI_CROSS_COMPILER),TRUE) - # Define RPI cross-compiler - #CC = armv6j-hardfloat-linux-gnueabi-gcc - CC = $(RPI_TOOLCHAIN)/bin/arm-linux-gnueabihf-gcc - endif -endif -ifeq ($(PLATFORM),PLATFORM_WEB) - # HTML5 emscripten compiler - # WARNING: To compile to HTML5, code must be redesigned - # to use emscripten.h and emscripten_set_main_loop() - CC = emcc -endif - -# Define default make program: Mingw32-make -MAKE = mingw32-make - -ifeq ($(PLATFORM),PLATFORM_DESKTOP) - ifeq ($(PLATFORM_OS),LINUX) - MAKE = make - endif - ifeq ($(PLATFORM_OS),OSX) - MAKE = make - endif -endif - -# Define compiler flags: -# -O1 defines optimization level -# -g include debug information on compilation -# -s strip unnecessary data from build -# -Wall turns on most, but not all, compiler warnings -# -std=c99 defines C language mode (standard C from 1999 revision) -# -std=gnu99 defines C language mode (GNU C from 1999 revision) -# -Wno-missing-braces ignore invalid warning (GCC bug 53119) -# -D_DEFAULT_SOURCE use with -std=c99 on Linux and PLATFORM_WEB, required for timespec -CFLAGS += -O1 -s -Wall -std=c99 -D_DEFAULT_SOURCE -Wno-missing-braces - -ifeq ($(BUILD_MODE),DEBUG) - CFLAGS += -g -endif - -# Additional flags for compiler (if desired) -#CFLAGS += -Wextra -Wmissing-prototypes -Wstrict-prototypes -ifeq ($(PLATFORM),PLATFORM_DESKTOP) - ifeq ($(PLATFORM_OS),WINDOWS) - # resource file contains windows executable icon and properties - # -Wl,--subsystem,windows hides the console window - CFLAGS += $(RAYLIB_PATH)/src/raylib.rc.data -Wl,--subsystem,windows - endif - ifeq ($(PLATFORM_OS),LINUX) - ifeq ($(RAYLIB_LIBTYPE),STATIC) - CFLAGS += -D_DEFAULT_SOURCE - endif - ifeq ($(RAYLIB_LIBTYPE),SHARED) - # Explicitly enable runtime link to libraylib.so - CFLAGS += -Wl,-rpath,$(EXAMPLE_RUNTIME_PATH) - endif - endif -endif -ifeq ($(PLATFORM),PLATFORM_RPI) - CFLAGS += -std=gnu99 -endif -ifeq ($(PLATFORM),PLATFORM_WEB) - # -Os # size optimization - # -O2 # optimization level 2, if used, also set --memory-init-file 0 - # -sUSE_GLFW=3 # Use glfw3 library (context/input management) - # -sALLOW_MEMORY_GROWTH=1 # to allow memory resizing -> WARNING: Audio buffers could FAIL! - # -sTOTAL_MEMORY=16777216 # to specify heap memory size (default = 16MB) (67108864 = 64MB) - # -sUSE_PTHREADS=1 # multithreading support - # -sWASM=0 # disable Web Assembly, emitted by default - # -sASYNCIFY # lets synchronous C/C++ code interact with asynchronous JS - # -sFORCE_FILESYSTEM=1 # force filesystem to load/save files data - # -sASSERTIONS=1 # enable runtime checks for common memory allocation errors (-O1 and above turn it off) - # -sMINIFY_HTML=0 # minify generated html from shell.html - # --profiling # include information for code profiling - # --memory-init-file 0 # to avoid an external memory initialization code file (.mem) - # --preload-file resources # specify a resources folder for data compilation - # --source-map-base # allow debugging in browser with source map - # --shell-file shell.html # define a custom shell .html and output extension - CFLAGS += -Os -sUSE_GLFW=3 -sTOTAL_MEMORY=16777216 --preload-file resources -sMINIFY_HTML=0 - ifeq ($(BUILD_MODE), DEBUG) - CFLAGS += -sASSERTIONS=1 --profiling - endif - - # Define a custom shell .html and output extension - CFLAGS += --shell-file $(RAYLIB_PATH)/src/shell.html - EXT = .html -endif - -# Define include paths for required headers -# NOTE: Several external required libraries (stb and others) -INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external - -# Define additional directories containing required header files -ifeq ($(PLATFORM),PLATFORM_RPI) - # RPI required libraries - INCLUDE_PATHS += -I/opt/vc/include - INCLUDE_PATHS += -I/opt/vc/include/interface/vmcs_host/linux - INCLUDE_PATHS += -I/opt/vc/include/interface/vcos/pthreads -endif -ifeq ($(PLATFORM),PLATFORM_DESKTOP) - ifeq ($(PLATFORM_OS),BSD) - # Consider -L$(RAYLIB_H_INSTALL_PATH) - INCLUDE_PATHS += -I/usr/local/include - endif - ifeq ($(PLATFORM_OS),LINUX) - # Reset everything. - # Precedence: immediately local, installed version, raysan5 provided libs -I$(RAYLIB_H_INSTALL_PATH) -I$(RAYLIB_PATH)/release/include - INCLUDE_PATHS = -I$(RAYLIB_H_INSTALL_PATH) -isystem. -isystem$(RAYLIB_PATH)/src -isystem$(RAYLIB_PATH)/release/include -isystem$(RAYLIB_PATH)/src/external - endif -endif - -# Define library paths containing required libs. -LDFLAGS = -L. -L$(RAYLIB_RELEASE_PATH) -L$(RAYLIB_PATH)/src - -ifeq ($(PLATFORM),PLATFORM_DESKTOP) - ifeq ($(PLATFORM_OS),BSD) - # Consider -L$(RAYLIB_INSTALL_PATH) - LDFLAGS += -L. -Lsrc -L/usr/local/lib - endif - ifeq ($(PLATFORM_OS),LINUX) - # Reset everything. - # Precedence: immediately local, installed version, raysan5 provided libs - LDFLAGS = -L. -L$(RAYLIB_INSTALL_PATH) -L$(RAYLIB_RELEASE_PATH) - endif -endif - -ifeq ($(PLATFORM),PLATFORM_RPI) - LDFLAGS += -L/opt/vc/lib -endif - -# Define any libraries required on linking -# if you want to link libraries (libname.so or libname.a), use the -lname -ifeq ($(PLATFORM),PLATFORM_DESKTOP) - ifeq ($(PLATFORM_OS),WINDOWS) - # Libraries for Windows desktop compilation - # NOTE: WinMM library required to set high-res timer resolution - LDLIBS = -lraylib -lopengl32 -lgdi32 -lwinmm - endif - ifeq ($(PLATFORM_OS),LINUX) - # Libraries for Debian GNU/Linux desktop compiling - # NOTE: Required packages: libegl1-mesa-dev - LDLIBS = -lraylib -lGL -lm -lpthread -ldl -lrt - - # On X11 requires also below libraries - LDLIBS += -lX11 - # NOTE: It seems additional libraries are not required any more, latest GLFW just dlopen them - #LDLIBS += -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor - - # On Wayland windowing system, additional libraries requires - ifeq ($(USE_WAYLAND_DISPLAY),TRUE) - LDLIBS += -lwayland-client -lwayland-cursor -lwayland-egl -lxkbcommon - endif - # Explicit link to libc - ifeq ($(RAYLIB_LIBTYPE),SHARED) - LDLIBS += -lc - endif - endif - ifeq ($(PLATFORM_OS),OSX) - # Libraries for OSX 10.9 desktop compiling - # NOTE: Required packages: libopenal-dev libegl1-mesa-dev - LDLIBS = -lraylib -framework OpenGL -framework OpenAL -framework Cocoa - endif - ifeq ($(PLATFORM_OS),BSD) - # Libraries for FreeBSD, OpenBSD, NetBSD, DragonFly desktop compiling - # NOTE: Required packages: mesa-libs - LDLIBS = -lraylib -lGL -lpthread -lm - - # On XWindow requires also below libraries - LDLIBS += -lX11 -lXrandr -lXinerama -lXi -lXxf86vm -lXcursor - endif - ifeq ($(USE_EXTERNAL_GLFW),TRUE) - # NOTE: It could require additional packages installed: libglfw3-dev - LDLIBS += -lglfw - endif -endif -ifeq ($(PLATFORM),PLATFORM_RPI) - # Libraries for Raspberry Pi compiling - # NOTE: Required packages: libasound2-dev (ALSA) - LDLIBS = -lraylib -lbrcmGLESv2 -lbrcmEGL -lpthread -lrt -lm -lbcm_host -ldl -endif -ifeq ($(PLATFORM),PLATFORM_WEB) - # Libraries for web (HTML5) compiling - LDLIBS = $(RAYLIB_RELEASE_PATH)/libraylib.bc -endif - -# Define a recursive wildcard function -rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d)) - -# Define all source files required -SRC_DIR = src -OBJ_DIR = obj - -# Define all object files from source files -SRC = $(call rwildcard, *.c, *.h) -#OBJS = $(SRC:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o) -OBJS = main.c - -# For Android platform we call a custom Makefile.Android -ifeq ($(PLATFORM),PLATFORM_ANDROID) - MAKEFILE_PARAMS = -f Makefile.Android - export PROJECT_NAME - export SRC_DIR -else - MAKEFILE_PARAMS = $(PROJECT_NAME) -endif - -# Default target entry -# NOTE: We call this Makefile target or Makefile.Android target -all: - $(MAKE) $(MAKEFILE_PARAMS) - -# Project target defined by PROJECT_NAME -$(PROJECT_NAME): $(OBJS) - $(CC) -o $(PROJECT_NAME)$(EXT) $(OBJS) $(CFLAGS) $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) -D$(PLATFORM) - -# Compile source files -# NOTE: This pattern will compile every module defined on $(OBJS) -#%.o: %.c -$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c - $(CC) -c $< -o $@ $(CFLAGS) $(INCLUDE_PATHS) -D$(PLATFORM) - -# Clean everything -clean: -ifeq ($(PLATFORM),PLATFORM_DESKTOP) - ifeq ($(PLATFORM_OS),WINDOWS) - del *.o *.exe /s - endif - ifeq ($(PLATFORM_OS),LINUX) - find -type f -executable | xargs file -i | grep -E 'x-object|x-archive|x-sharedlib|x-executable' | rev | cut -d ':' -f 2- | rev | xargs rm -fv - endif - ifeq ($(PLATFORM_OS),OSX) - find . -type f -perm +ugo+x -delete - rm -f *.o - endif -endif -ifeq ($(PLATFORM),PLATFORM_RPI) - find . -type f -executable -delete - rm -fv *.o -endif -ifeq ($(PLATFORM),PLATFORM_WEB) - del *.o *.html *.js -endif - @echo Cleaning done - diff --git a/projects/4coder/Makefile.Android b/projects/4coder/Makefile.Android deleted file mode 100644 index 9e6773651..000000000 --- a/projects/4coder/Makefile.Android +++ /dev/null @@ -1,300 +0,0 @@ -#************************************************************************************************** -# -# raylib makefile for Android project (APK building) -# -# Copyright (c) 2017 Ramon Santamaria (@raysan5) -# -# This software is provided "as-is", without any express or implied warranty. In no event -# will the authors be held liable for any damages arising from the use of this software. -# -# Permission is granted to anyone to use this software for any purpose, including commercial -# applications, and to alter it and redistribute it freely, subject to the following restrictions: -# -# 1. The origin of this software must not be misrepresented; you must not claim that you -# wrote the original software. If you use this software in a product, an acknowledgment -# in the product documentation would be appreciated but is not required. -# -# 2. Altered source versions must be plainly marked as such, and must not be misrepresented -# as being the original software. -# -# 3. This notice may not be removed or altered from any source distribution. -# -#************************************************************************************************** - -# Define required raylib variables -PLATFORM ?= PLATFORM_ANDROID -RAYLIB_PATH ?= ..\.. - -# Define Android architecture (armeabi-v7a, arm64-v8a, x86, x86-64) and API version -ANDROID_ARCH ?= ARM -ANDROID_API_VERSION = 21 -ifeq ($(ANDROID_ARCH),ARM) - ANDROID_ARCH_NAME = armeabi-v7a -endif -ifeq ($(ANDROID_ARCH),ARM64) - ANDROID_ARCH_NAME = arm64-v8a -endif - -# Required path variables -# NOTE: JAVA_HOME must be set to JDK -JAVA_HOME ?= C:/JavaJDK -ANDROID_HOME = C:/android-sdk -ANDROID_TOOLCHAIN = C:/android_toolchain_$(ANDROID_ARCH)_API$(ANDROID_API_VERSION) -ANDROID_BUILD_TOOLS = $(ANDROID_HOME)/build-tools/28.0.1 -ANDROID_PLATFORM_TOOLS = $(ANDROID_HOME)/platform-tools - -# Android project configuration variables -PROJECT_NAME ?= raylib_game -PROJECT_LIBRARY_NAME ?= main -PROJECT_BUILD_PATH ?= android.$(PROJECT_NAME) -PROJECT_RESOURCES_PATH ?= resources -PROJECT_SOURCE_FILES ?= raylib_game.c - -# Some source files are placed in directories, when compiling to some -# output directory other than source, that directory must pre-exist. -# Here we get a list of required folders that need to be created on -# code output folder $(PROJECT_BUILD_PATH)\obj to avoid GCC errors. -PROJECT_SOURCE_DIRS = $(sort $(dir $(PROJECT_SOURCE_FILES))) - -# Android app configuration variables -APP_LABEL_NAME ?= rGame -APP_COMPANY_NAME ?= raylib -APP_PRODUCT_NAME ?= rgame -APP_VERSION_CODE ?= 1 -APP_VERSION_NAME ?= 1.0 -APP_ICON_LDPI ?= $(RAYLIB_PATH)\logo\raylib_36x36.png -APP_ICON_MDPI ?= $(RAYLIB_PATH)\logo\raylib_48x48.png -APP_ICON_HDPI ?= $(RAYLIB_PATH)\logo\raylib_72x72.png -APP_SCREEN_ORIENTATION ?= landscape -APP_KEYSTORE_PASS ?= raylib - -# Library type used for raylib: STATIC (.a) or SHARED (.so/.dll) -RAYLIB_LIBTYPE ?= STATIC - -# Library path for libraylib.a/libraylib.so -RAYLIB_LIB_PATH = $(RAYLIB_PATH)\src - -# Shared libs must be added to APK if required -# NOTE: Generated NativeLoader.java automatically load those libraries -ifeq ($(RAYLIB_LIBTYPE),SHARED) - PROJECT_SHARED_LIBS = lib/$(ANDROID_ARCH_NAME)/libraylib.so -endif - -# Compiler and archiver -# NOTE: GCC is being deprecated in Android NDK r16 -ifeq ($(ANDROID_ARCH),ARM) - CC = $(ANDROID_TOOLCHAIN)/bin/arm-linux-androideabi-clang - AR = $(ANDROID_TOOLCHAIN)/bin/arm-linux-androideabi-ar -endif -ifeq ($(ANDROID_ARCH),ARM64) - CC = $(ANDROID_TOOLCHAIN)/bin/aarch64-linux-android-clang - AR = $(ANDROID_TOOLCHAIN)/bin/aarch64-linux-android-ar -endif - -# Compiler flags for arquitecture -ifeq ($(ANDROID_ARCH),ARM) - CFLAGS = -std=c99 -march=armv7-a -mfloat-abi=softfp -mfpu=vfpv3-d16 -endif -ifeq ($(ANDROID_ARCH),ARM64) - CFLAGS = -std=c99 -mfix-cortex-a53-835769 -endif -# Compilation functions attributes options -CFLAGS += -ffunction-sections -funwind-tables -fstack-protector-strong -fPIC -# Compiler options for the linker -CFLAGS += -Wall -Wa,--noexecstack -Wformat -Werror=format-security -no-canonical-prefixes -# Preprocessor macro definitions -CFLAGS += -DANDROID -DPLATFORM_ANDROID -D__ANDROID_API__=$(ANDROID_API_VERSION) - -# Paths containing required header files -INCLUDE_PATHS = -I. -I$(RAYLIB_PATH)/src -I$(RAYLIB_PATH)/src/external/android/native_app_glue - -# Linker options -LDFLAGS = -Wl,-soname,lib$(PROJECT_LIBRARY_NAME).so -Wl,--exclude-libs,libatomic.a -LDFLAGS += -Wl,--build-id -Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -Wl,--warn-shared-textrel -Wl,--fatal-warnings -# Force linking of library module to define symbol -LDFLAGS += -u ANativeActivity_onCreate -# Library paths containing required libs -LDFLAGS += -L. -L$(PROJECT_BUILD_PATH)/obj -L$(PROJECT_BUILD_PATH)/lib/$(ANDROID_ARCH_NAME) -L$(ANDROID_TOOLCHAIN)\sysroot\usr\lib - -# Define any libraries to link into executable -# if you want to link libraries (libname.so or libname.a), use the -lname -LDLIBS = -lm -lc -lraylib -llog -landroid -lEGL -lGLESv2 -lOpenSLES -ldl - -# Generate target objects list from PROJECT_SOURCE_FILES -OBJS = $(patsubst %.c, $(PROJECT_BUILD_PATH)/obj/%.o, $(PROJECT_SOURCE_FILES)) - -# Android APK building process... some steps required... -# NOTE: typing 'make' will invoke the default target entry called 'all', -all: create_temp_project_dirs \ - copy_project_required_libs \ - copy_project_resources \ - generate_loader_script \ - generate_android_manifest \ - generate_apk_keystore \ - config_project_package \ - compile_project_code \ - compile_project_class \ - compile_project_class_dex \ - create_project_apk_package \ - sign_project_apk_package \ - zipalign_project_apk_package - -# Create required temp directories for APK building -create_temp_project_dirs: - if not exist $(PROJECT_BUILD_PATH) mkdir $(PROJECT_BUILD_PATH) - if not exist $(PROJECT_BUILD_PATH)\obj mkdir $(PROJECT_BUILD_PATH)\obj - if not exist $(PROJECT_BUILD_PATH)\src mkdir $(PROJECT_BUILD_PATH)\src - if not exist $(PROJECT_BUILD_PATH)\src\com mkdir $(PROJECT_BUILD_PATH)\src\com - if not exist $(PROJECT_BUILD_PATH)\src\com\$(APP_COMPANY_NAME) mkdir $(PROJECT_BUILD_PATH)\src\com\$(APP_COMPANY_NAME) - if not exist $(PROJECT_BUILD_PATH)\src\com\$(APP_COMPANY_NAME)\$(APP_PRODUCT_NAME) mkdir $(PROJECT_BUILD_PATH)\src\com\$(APP_COMPANY_NAME)\$(APP_PRODUCT_NAME) - if not exist $(PROJECT_BUILD_PATH)\lib mkdir $(PROJECT_BUILD_PATH)\lib - if not exist $(PROJECT_BUILD_PATH)\lib\$(ANDROID_ARCH_NAME) mkdir $(PROJECT_BUILD_PATH)\lib\$(ANDROID_ARCH_NAME) - if not exist $(PROJECT_BUILD_PATH)\bin mkdir $(PROJECT_BUILD_PATH)\bin - if not exist $(PROJECT_BUILD_PATH)\res mkdir $(PROJECT_BUILD_PATH)\res - if not exist $(PROJECT_BUILD_PATH)\res\drawable-ldpi mkdir $(PROJECT_BUILD_PATH)\res\drawable-ldpi - if not exist $(PROJECT_BUILD_PATH)\res\drawable-mdpi mkdir $(PROJECT_BUILD_PATH)\res\drawable-mdpi - if not exist $(PROJECT_BUILD_PATH)\res\drawable-hdpi mkdir $(PROJECT_BUILD_PATH)\res\drawable-hdpi - if not exist $(PROJECT_BUILD_PATH)\res\values mkdir $(PROJECT_BUILD_PATH)\res\values - if not exist $(PROJECT_BUILD_PATH)\assets mkdir $(PROJECT_BUILD_PATH)\assets - if not exist $(PROJECT_BUILD_PATH)\assets\$(PROJECT_RESOURCES_PATH) mkdir $(PROJECT_BUILD_PATH)\assets\$(PROJECT_RESOURCES_PATH) - if not exist $(PROJECT_BUILD_PATH)\obj\screens mkdir $(PROJECT_BUILD_PATH)\obj\screens - $(foreach dir, $(PROJECT_SOURCE_DIRS), $(call create_dir, $(dir))) - -define create_dir - if not exist $(PROJECT_BUILD_PATH)\obj\$(1) mkdir $(PROJECT_BUILD_PATH)\obj\$(1) -endef - -# Copy required shared libs for integration into APK -# NOTE: If using shared libs they are loaded by generated NativeLoader.java -copy_project_required_libs: -ifeq ($(RAYLIB_LIBTYPE),SHARED) - copy /Y $(RAYLIB_LIB_PATH)\libraylib.so $(PROJECT_BUILD_PATH)\lib\$(ANDROID_ARCH_NAME)\libraylib.so -endif -ifeq ($(RAYLIB_LIBTYPE),STATIC) - copy /Y $(RAYLIB_LIB_PATH)\libraylib.a $(PROJECT_BUILD_PATH)\lib\$(ANDROID_ARCH_NAME)\libraylib.a -endif - -# Copy project required resources: strings.xml, icon.png, assets -# NOTE: Required strings.xml is generated and game resources are copied to assets folder -# TODO: Review xcopy usage, it can not be found in some systems! -copy_project_resources: - copy $(APP_ICON_LDPI) $(PROJECT_BUILD_PATH)\res\drawable-ldpi\icon.png /Y - copy $(APP_ICON_MDPI) $(PROJECT_BUILD_PATH)\res\drawable-mdpi\icon.png /Y - copy $(APP_ICON_HDPI) $(PROJECT_BUILD_PATH)\res\drawable-hdpi\icon.png /Y - @echo ^ > $(PROJECT_BUILD_PATH)/res/values/strings.xml - @echo ^^$(APP_LABEL_NAME)^^ >> $(PROJECT_BUILD_PATH)/res/values/strings.xml - if exist $(PROJECT_RESOURCES_PATH) C:\Windows\System32\xcopy $(PROJECT_RESOURCES_PATH) $(PROJECT_BUILD_PATH)\assets\$(PROJECT_RESOURCES_PATH) /Y /E /F - -# Generate NativeLoader.java to load required shared libraries -# NOTE: Probably not the bet way to generate this file... but it works. -generate_loader_script: - @echo package com.$(APP_COMPANY_NAME).$(APP_PRODUCT_NAME); > $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java - @echo. >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java - @echo public class NativeLoader extends android.app.NativeActivity { >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java - @echo static { >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java -ifeq ($(RAYLIB_LIBTYPE),SHARED) - @echo System.loadLibrary("raylib"); >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java -endif - @echo System.loadLibrary("$(PROJECT_LIBRARY_NAME)"); >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java - @echo } >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java - @echo } >> $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java - -# Generate AndroidManifest.xml with all the required options -# NOTE: Probably not the bet way to generate this file... but it works. -generate_android_manifest: - @echo ^ > $(PROJECT_BUILD_PATH)/AndroidManifest.xml - @echo ^> $(PROJECT_BUILD_PATH)/AndroidManifest.xml - @echo package="com.$(APP_COMPANY_NAME).$(APP_PRODUCT_NAME)" >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml - @echo android:versionCode="$(APP_VERSION_CODE)" android:versionName="$(APP_VERSION_NAME)" ^> >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml - @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml - @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml - @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml - @echo ^> $(PROJECT_BUILD_PATH)/AndroidManifest.xml - @echo android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml - @echo android:configChanges="orientation|keyboardHidden|screenSize" >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml - @echo android:screenOrientation="$(APP_SCREEN_ORIENTATION)" android:launchMode="singleTask" >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml - @echo android:clearTaskOnLaunch="true"^> >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml - @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml - @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml - @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml - @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml - @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml - @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml - @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml - @echo ^ >> $(PROJECT_BUILD_PATH)/AndroidManifest.xml - -# Generate storekey for APK signing: $(PROJECT_NAME).keystore -# NOTE: Configure here your Distinguished Names (-dname) if required! -generate_apk_keystore: - if not exist $(PROJECT_BUILD_PATH)/$(PROJECT_NAME).keystore $(JAVA_HOME)/bin/keytool -genkeypair -validity 1000 -dname "CN=$(APP_COMPANY_NAME),O=Android,C=ES" -keystore $(PROJECT_BUILD_PATH)/$(PROJECT_NAME).keystore -storepass $(APP_KEYSTORE_PASS) -keypass $(APP_KEYSTORE_PASS) -alias $(PROJECT_NAME)Key -keyalg RSA - -# Config project package and resource using AndroidManifest.xml and res/values/strings.xml -# NOTE: Generates resources file: src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/R.java -config_project_package: - $(ANDROID_BUILD_TOOLS)/aapt package -f -m -S $(PROJECT_BUILD_PATH)/res -J $(PROJECT_BUILD_PATH)/src -M $(PROJECT_BUILD_PATH)/AndroidManifest.xml -I $(ANDROID_HOME)/platforms/android-$(ANDROID_API_VERSION)/android.jar - -# Compile native_app_glue code as static library: obj/libnative_app_glue.a -compile_native_app_glue: - $(CC) -c $(RAYLIB_PATH)/src/external/android/native_app_glue/android_native_app_glue.c -o $(PROJECT_BUILD_PATH)/obj/native_app_glue.o $(CFLAGS) - $(AR) rcs $(PROJECT_BUILD_PATH)/obj/libnative_app_glue.a $(PROJECT_BUILD_PATH)/obj/native_app_glue.o - -# Compile project code into a shared library: lib/lib$(PROJECT_LIBRARY_NAME).so -compile_project_code: $(OBJS) - $(CC) -o $(PROJECT_BUILD_PATH)/lib/$(ANDROID_ARCH_NAME)/lib$(PROJECT_LIBRARY_NAME).so $(OBJS) -shared $(INCLUDE_PATHS) $(LDFLAGS) $(LDLIBS) - -# Compile all .c files required into object (.o) files -# NOTE: Those files will be linked into a shared library -$(PROJECT_BUILD_PATH)/obj/%.o:%.c - $(CC) -c $^ -o $@ $(INCLUDE_PATHS) $(CFLAGS) --sysroot=$(ANDROID_TOOLCHAIN)/sysroot - -# Compile project .java code into .class (Java bytecode) -compile_project_class: - $(JAVA_HOME)/bin/javac -verbose -source 1.7 -target 1.7 -d $(PROJECT_BUILD_PATH)/obj -bootclasspath $(JAVA_HOME)/jre/lib/rt.jar -classpath $(ANDROID_HOME)/platforms/android-$(ANDROID_API_VERSION)/android.jar;$(PROJECT_BUILD_PATH)/obj -sourcepath $(PROJECT_BUILD_PATH)/src $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/R.java $(PROJECT_BUILD_PATH)/src/com/$(APP_COMPANY_NAME)/$(APP_PRODUCT_NAME)/NativeLoader.java - -# Compile .class files into Dalvik executable bytecode (.dex) -# NOTE: Since Android 5.0, Dalvik interpreter (JIT) has been replaced by ART (AOT) -compile_project_class_dex: - $(ANDROID_BUILD_TOOLS)/dx --verbose --dex --output=$(PROJECT_BUILD_PATH)/bin/classes.dex $(PROJECT_BUILD_PATH)/obj - -# Create Android APK package: bin/$(PROJECT_NAME).unsigned.apk -# NOTE: Requires compiled classes.dex and lib$(PROJECT_LIBRARY_NAME).so -# NOTE: Use -A resources to define additional directory in which to find raw asset files -create_project_apk_package: - $(ANDROID_BUILD_TOOLS)/aapt package -f -M $(PROJECT_BUILD_PATH)/AndroidManifest.xml -S $(PROJECT_BUILD_PATH)/res -A $(PROJECT_BUILD_PATH)/assets -I $(ANDROID_HOME)/platforms/android-$(ANDROID_API_VERSION)/android.jar -F $(PROJECT_BUILD_PATH)/bin/$(PROJECT_NAME).unsigned.apk $(PROJECT_BUILD_PATH)/bin - cd $(PROJECT_BUILD_PATH) && $(ANDROID_BUILD_TOOLS)/aapt add bin/$(PROJECT_NAME).unsigned.apk lib/$(ANDROID_ARCH_NAME)/lib$(PROJECT_LIBRARY_NAME).so $(PROJECT_SHARED_LIBS) - -# Create signed APK package using generated Key: bin/$(PROJECT_NAME).signed.apk -sign_project_apk_package: - $(JAVA_HOME)/bin/jarsigner -keystore $(PROJECT_BUILD_PATH)/$(PROJECT_NAME).keystore -storepass $(APP_KEYSTORE_PASS) -keypass $(APP_KEYSTORE_PASS) -signedjar $(PROJECT_BUILD_PATH)/bin/$(PROJECT_NAME).signed.apk $(PROJECT_BUILD_PATH)/bin/$(PROJECT_NAME).unsigned.apk $(PROJECT_NAME)Key - -# Create zip-aligned APK package: $(PROJECT_NAME).apk -zipalign_project_apk_package: - $(ANDROID_BUILD_TOOLS)/zipalign -f 4 $(PROJECT_BUILD_PATH)/bin/$(PROJECT_NAME).signed.apk $(PROJECT_NAME).apk - -# Install $(PROJECT_NAME).apk to default emulator/device -# NOTE: Use -e (emulator) or -d (device) parameters if required -install: - $(ANDROID_PLATFORM_TOOLS)/adb install --abi $(ANDROID_ARCH_NAME) -rds $(PROJECT_NAME).apk - -# Check supported ABI for the device (armeabi-v7a, arm64-v8a, x86, x86_64) -check_device_abi: - $(ANDROID_PLATFORM_TOOLS)/adb shell getprop ro.product.cpu.abi - -# Monitorize output log coming from device, only raylib tag -logcat: - $(ANDROID_PLATFORM_TOOLS)/adb logcat -c - $(ANDROID_PLATFORM_TOOLS)/adb logcat raylib:V *:S - -# Install and monitorize $(PROJECT_NAME).apk to default emulator/device -deploy: - $(ANDROID_PLATFORM_TOOLS)/adb install -r $(PROJECT_NAME).apk - $(ANDROID_PLATFORM_TOOLS)/adb logcat -c - $(ANDROID_PLATFORM_TOOLS)/adb logcat raylib:V *:S - -#$(ANDROID_PLATFORM_TOOLS)/adb logcat *:W - -# Clean everything -clean: - del $(PROJECT_BUILD_PATH)\* /f /s /q - rmdir $(PROJECT_BUILD_PATH) /s /q - @echo Cleaning done diff --git a/projects/4coder/main.c b/projects/4coder/main.c deleted file mode 100644 index 78e1519cb..000000000 --- a/projects/4coder/main.c +++ /dev/null @@ -1,40 +0,0 @@ -#include -#include "raylib.h" - -int main() -{ - int screenWidth = 800; - int screenHeight = 450; - - InitWindow(screenWidth, screenHeight, "raylib"); - - Camera cam; - cam.position = (Vector3){ 0.0f, 10.0f, 8.f }; - cam.target = (Vector3){ 0.0f, 0.0f, 0.0f }; - cam.up = (Vector3){ 0.0f, 1.f, 0.0f }; - cam.fovy = 60.0f; - - Vector3 cubePos = { 0.0f, 0.0f, 0.0f }; - - SetTargetFPS(60); - - while (!WindowShouldClose()) - { - cam.position.x = sin(GetTime())*10.0f; - cam.position.z = cos(GetTime())*10.0f; - - BeginDrawing(); - ClearBackground(RAYWHITE); - BeginMode3D(cam); - DrawCube(cubePos, 2.f, 2.f, 2.f, RED); - DrawCubeWires(cubePos, 2.f, 2.f, 2.f, MAROON); - DrawGrid(10, 1.f); - EndMode3D(); - DrawText("This is a raylib example", 10, 40, 20, DARKGRAY); - DrawFPS(10, 10); - EndDrawing(); - } - - CloseWindow(); - return 0; -} diff --git a/projects/4coder/project.4coder b/projects/4coder/project.4coder deleted file mode 100644 index 568de79bd..000000000 --- a/projects/4coder/project.4coder +++ /dev/null @@ -1,54 +0,0 @@ -version(1); - -project_name = "raylib-example"; - -patterns = { -"*.cpp", -"*.c", -"*.h", -"*.bat", -"*.sh", -"*.4coder", -"Makefile", -}; - -blacklist_patterns = { -".*", -}; - -load_paths = { - { { {".", .relative = true, .recursive = true, } }, .os = "win" }, - { { {".", .relative = true, .recursive = true, } }, .os = "linux" }, - { { {".", .relative = true, .recursive = true, } }, .os = "mac" }, -}; - -command_list = { - { .name = "clean", - .out = "*clean*", .footer_panel = true, .save_dirty_files = false, .cursor_at_end = true, - .cmd = { - {"mingw32-make clean", .os = "win"}, - {"make clean", .os = "linux"}, - {"make clean", .os = "mac"}, - }, - }, - { .name = "build", - .out = "*compile*", .footer_panel = true, .save_dirty_files = true, .cursor_at_end = false, - .cmd = { - {"mingw32-make", .os = "win"}, - {"make", .os = "linux"}, - {"make", .os = "mac"}, - }, - }, - { .name = "run", - .out = "*run*", .footer_panel = true, .save_dirty_files = false, .cursor_at_end = true, - .cmd = { - {".\game.exe", .os = "win"}, - {"./game", .os = "linux"}, - {"./game", .os = "mac"}, - }, - }, -}; - -fkey_command[3] = "clean"; -fkey_command[4] = "build"; -fkey_command[5] = "run"; From f1d44c166fd7d06c9e7f07ae91e88f7d14112933 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 16 Jul 2026 15:08:46 +0200 Subject: [PATCH 68/94] REMOVED: Unmaintained project: VS2019-Android --- projects/VS2019-Android/raylib_android.sln | 75 --- .../android_native_app_glue.c | 437 ------------------ .../android_native_app_glue.h | 344 -------------- .../raylib_android.NativeActivity/main.c | 64 --- .../raylib_android.NativeActivity.vcxproj | 226 --------- ...lib_android.NativeActivity.vcxproj.filters | 10 - ...raylib_android.NativeActivity.vcxproj.user | 4 - .../AndroidManifest.xml | 22 - .../raylib_android.Packaging/build.xml | 90 ---- .../project.properties | 3 - .../raylib_android.Packaging.androidproj | 134 ------ .../res/values/strings.xml | 4 - 12 files changed, 1413 deletions(-) delete mode 100644 projects/VS2019-Android/raylib_android.sln delete mode 100644 projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/android_native_app_glue.c delete mode 100644 projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/android_native_app_glue.h delete mode 100644 projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/main.c delete mode 100644 projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/raylib_android.NativeActivity.vcxproj delete mode 100644 projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/raylib_android.NativeActivity.vcxproj.filters delete mode 100644 projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/raylib_android.NativeActivity.vcxproj.user delete mode 100644 projects/VS2019-Android/raylib_android/raylib_android.Packaging/AndroidManifest.xml delete mode 100644 projects/VS2019-Android/raylib_android/raylib_android.Packaging/build.xml delete mode 100644 projects/VS2019-Android/raylib_android/raylib_android.Packaging/project.properties delete mode 100644 projects/VS2019-Android/raylib_android/raylib_android.Packaging/raylib_android.Packaging.androidproj delete mode 100644 projects/VS2019-Android/raylib_android/raylib_android.Packaging/res/values/strings.xml diff --git a/projects/VS2019-Android/raylib_android.sln b/projects/VS2019-Android/raylib_android.sln deleted file mode 100644 index ec1880c0e..000000000 --- a/projects/VS2019-Android/raylib_android.sln +++ /dev/null @@ -1,75 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.31702.278 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "raylib_android", "raylib_android", "{5C24BC76-8848-40EA-9BBB-A544648D8D5B}" -EndProject -Project("{39E2626F-3545-4960-A6E8-258AD8476CE5}") = "raylib_android.Packaging", "raylib_android\raylib_android.Packaging\raylib_android.Packaging.androidproj", "{B2231F0D-52DA-4C55-8998-5886F766553C}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "raylib_android.NativeActivity", "raylib_android\raylib_android.NativeActivity\raylib_android.NativeActivity.vcxproj", "{BFB31759-4FCA-4503-BC7C-A97F705EFDB2}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|ARM = Debug|ARM - Debug|ARM64 = Debug|ARM64 - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|ARM = Release|ARM - Release|ARM64 = Release|ARM64 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|ARM.ActiveCfg = Debug|ARM - {B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|ARM.Build.0 = Debug|ARM - {B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|ARM.Deploy.0 = Debug|ARM - {B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|ARM64.Build.0 = Debug|ARM64 - {B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|ARM64.Deploy.0 = Debug|ARM64 - {B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|x64.ActiveCfg = Debug|x64 - {B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|x64.Build.0 = Debug|x64 - {B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|x64.Deploy.0 = Debug|x64 - {B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|x86.ActiveCfg = Debug|x86 - {B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|x86.Build.0 = Debug|x86 - {B2231F0D-52DA-4C55-8998-5886F766553C}.Debug|x86.Deploy.0 = Debug|x86 - {B2231F0D-52DA-4C55-8998-5886F766553C}.Release|ARM.ActiveCfg = Release|ARM - {B2231F0D-52DA-4C55-8998-5886F766553C}.Release|ARM.Build.0 = Release|ARM - {B2231F0D-52DA-4C55-8998-5886F766553C}.Release|ARM.Deploy.0 = Release|ARM - {B2231F0D-52DA-4C55-8998-5886F766553C}.Release|ARM64.ActiveCfg = Release|ARM64 - {B2231F0D-52DA-4C55-8998-5886F766553C}.Release|ARM64.Build.0 = Release|ARM64 - {B2231F0D-52DA-4C55-8998-5886F766553C}.Release|ARM64.Deploy.0 = Release|ARM64 - {B2231F0D-52DA-4C55-8998-5886F766553C}.Release|x64.ActiveCfg = Release|x64 - {B2231F0D-52DA-4C55-8998-5886F766553C}.Release|x64.Build.0 = Release|x64 - {B2231F0D-52DA-4C55-8998-5886F766553C}.Release|x64.Deploy.0 = Release|x64 - {B2231F0D-52DA-4C55-8998-5886F766553C}.Release|x86.ActiveCfg = Release|x86 - {B2231F0D-52DA-4C55-8998-5886F766553C}.Release|x86.Build.0 = Release|x86 - {B2231F0D-52DA-4C55-8998-5886F766553C}.Release|x86.Deploy.0 = Release|x86 - {BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Debug|ARM.ActiveCfg = Debug|ARM - {BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Debug|ARM.Build.0 = Debug|ARM - {BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Debug|ARM64.Build.0 = Debug|ARM64 - {BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Debug|x64.ActiveCfg = Debug|x64 - {BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Debug|x64.Build.0 = Debug|x64 - {BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Debug|x86.ActiveCfg = Debug|x86 - {BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Debug|x86.Build.0 = Debug|x86 - {BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Release|ARM.ActiveCfg = Release|ARM - {BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Release|ARM.Build.0 = Release|ARM - {BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Release|ARM64.ActiveCfg = Release|ARM64 - {BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Release|ARM64.Build.0 = Release|ARM64 - {BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Release|x64.ActiveCfg = Release|x64 - {BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Release|x64.Build.0 = Release|x64 - {BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Release|x86.ActiveCfg = Release|x86 - {BFB31759-4FCA-4503-BC7C-A97F705EFDB2}.Release|x86.Build.0 = Release|x86 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {B2231F0D-52DA-4C55-8998-5886F766553C} = {5C24BC76-8848-40EA-9BBB-A544648D8D5B} - {BFB31759-4FCA-4503-BC7C-A97F705EFDB2} = {5C24BC76-8848-40EA-9BBB-A544648D8D5B} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {B7ED0AA6-6B00-40AC-BF71-526D5BEEFC78} - EndGlobalSection -EndGlobal diff --git a/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/android_native_app_glue.c b/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/android_native_app_glue.c deleted file mode 100644 index 0b8379423..000000000 --- a/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/android_native_app_glue.c +++ /dev/null @@ -1,437 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * лицензировано по лицензии Apache License, версия 2.0 ( "Лицензия"); - *этот файл можно использовать только в соответствии с лицензией. - *Копию лицензии можно получить на веб-сайте - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - *Если только не требуется в соответствии с применимым законодательством или согласовано в письменном виде, программное обеспечение - * распространяется в рамках лицензии на УСЛОВИЯХ "КАК ЕСТЬ", - * БЕЗ ГАРАНТИЙ И УСЛОВИЙ ЛЮБОГО РОДА, явно выраженных и подразумеваемых. - * См. лицензию для получения информации об определенных разрешениях по использованию языка и - * ограничениях в рамках лицензии. - * - */ - -#include - -#include -#include -#include -#include -#include - -#include "android_native_app_glue.h" -#include - -#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__)) -#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "threaded_app", __VA_ARGS__)) - -/* Для отладочных построений необходимо всегда включать трассировку отладки в этой библиотеке*/ -#ifndef NDEBUG -# define LOGV(...) ((void)__android_log_print(ANDROID_LOG_VERBOSE, "threaded_app", __VA_ARGS__)) -#else -# define LOGV(...) ((void)0) -#endif - -static void free_saved_state(struct android_app* android_app) { - pthread_mutex_lock(&android_app->mutex); - if (android_app->savedState != NULL) { - free(android_app->savedState); - android_app->savedState = NULL; - android_app->savedStateSize = 0; - } - pthread_mutex_unlock(&android_app->mutex); -} - -int8_t android_app_read_cmd(struct android_app* android_app) { - int8_t cmd; - if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) { - switch (cmd) { - case APP_CMD_SAVE_STATE: - free_saved_state(android_app); - break; - } - return cmd; - } else { - LOGE("No data on command pipe!"); - } - return -1; -} - -static void print_cur_config(struct android_app* android_app) { - char lang[2], country[2]; - AConfiguration_getLanguage(android_app->config, lang); - AConfiguration_getCountry(android_app->config, country); - - LOGV("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d " - "keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d " - "modetype=%d modenight=%d", - AConfiguration_getMcc(android_app->config), - AConfiguration_getMnc(android_app->config), - lang[0], lang[1], country[0], country[1], - AConfiguration_getOrientation(android_app->config), - AConfiguration_getTouchscreen(android_app->config), - AConfiguration_getDensity(android_app->config), - AConfiguration_getKeyboard(android_app->config), - AConfiguration_getNavigation(android_app->config), - AConfiguration_getKeysHidden(android_app->config), - AConfiguration_getNavHidden(android_app->config), - AConfiguration_getSdkVersion(android_app->config), - AConfiguration_getScreenSize(android_app->config), - AConfiguration_getScreenLong(android_app->config), - AConfiguration_getUiModeType(android_app->config), - AConfiguration_getUiModeNight(android_app->config)); -} - -void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) { - switch (cmd) { - case APP_CMD_INPUT_CHANGED: - LOGV("APP_CMD_INPUT_CHANGED\n"); - pthread_mutex_lock(&android_app->mutex); - if (android_app->inputQueue != NULL) { - AInputQueue_detachLooper(android_app->inputQueue); - } - android_app->inputQueue = android_app->pendingInputQueue; - if (android_app->inputQueue != NULL) { - LOGV("Attaching input queue to looper"); - AInputQueue_attachLooper(android_app->inputQueue, - android_app->looper, LOOPER_ID_INPUT, NULL, - &android_app->inputPollSource); - } - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_INIT_WINDOW: - LOGV("APP_CMD_INIT_WINDOW\n"); - pthread_mutex_lock(&android_app->mutex); - android_app->window = android_app->pendingWindow; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_TERM_WINDOW: - LOGV("APP_CMD_TERM_WINDOW\n"); - pthread_cond_broadcast(&android_app->cond); - break; - - case APP_CMD_RESUME: - case APP_CMD_START: - case APP_CMD_PAUSE: - case APP_CMD_STOP: - LOGV("activityState=%d\n", cmd); - pthread_mutex_lock(&android_app->mutex); - android_app->activityState = cmd; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_CONFIG_CHANGED: - LOGV("APP_CMD_CONFIG_CHANGED\n"); - AConfiguration_fromAssetManager(android_app->config, - android_app->activity->assetManager); - print_cur_config(android_app); - break; - - case APP_CMD_DESTROY: - LOGV("APP_CMD_DESTROY\n"); - android_app->destroyRequested = 1; - break; - } -} - -void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd) { - switch (cmd) { - case APP_CMD_TERM_WINDOW: - LOGV("APP_CMD_TERM_WINDOW\n"); - pthread_mutex_lock(&android_app->mutex); - android_app->window = NULL; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_SAVE_STATE: - LOGV("APP_CMD_SAVE_STATE\n"); - pthread_mutex_lock(&android_app->mutex); - android_app->stateSaved = 1; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - break; - - case APP_CMD_RESUME: - free_saved_state(android_app); - break; - } -} - -static void android_app_destroy(struct android_app* android_app) { - LOGV("android_app_destroy!"); - free_saved_state(android_app); - pthread_mutex_lock(&android_app->mutex); - if (android_app->inputQueue != NULL) { - AInputQueue_detachLooper(android_app->inputQueue); - } - AConfiguration_delete(android_app->config); - android_app->destroyed = 1; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - // После этого нельзя изменять объект android_app. -} - -static void process_input(struct android_app* app, struct android_poll_source* source) { - AInputEvent* event = NULL; - while (AInputQueue_getEvent(app->inputQueue, &event) >= 0) { - LOGV("New input event: type=%d\n", AInputEvent_getType(event)); - if (AInputQueue_preDispatchEvent(app->inputQueue, event)) { - continue; - } - int32_t handled = 0; - if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event); - AInputQueue_finishEvent(app->inputQueue, event, handled); - } -} - -static void process_cmd(struct android_app* app, struct android_poll_source* source) { - int8_t cmd = android_app_read_cmd(app); - android_app_pre_exec_cmd(app, cmd); - if (app->onAppCmd != NULL) app->onAppCmd(app, cmd); - android_app_post_exec_cmd(app, cmd); -} - -static void* android_app_entry(void* param) { - struct android_app* android_app = (struct android_app*)param; - - android_app->config = AConfiguration_new(); - AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager); - - print_cur_config(android_app); - - android_app->cmdPollSource.id = LOOPER_ID_MAIN; - android_app->cmdPollSource.app = android_app; - android_app->cmdPollSource.process = process_cmd; - android_app->inputPollSource.id = LOOPER_ID_INPUT; - android_app->inputPollSource.app = android_app; - android_app->inputPollSource.process = process_input; - - ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS); - ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL, - &android_app->cmdPollSource); - android_app->looper = looper; - - pthread_mutex_lock(&android_app->mutex); - android_app->running = 1; - pthread_cond_broadcast(&android_app->cond); - pthread_mutex_unlock(&android_app->mutex); - - android_main(android_app); - - android_app_destroy(android_app); - return NULL; -} - -// -------------------------------------------------------------------- -// Взаимодействие NativeАctivity (вызванное из основного потока) -// -------------------------------------------------------------------- - -static struct android_app* android_app_create(ANativeActivity* activity, - void* savedState, size_t savedStateSize) { - struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app)); - memset(android_app, 0, sizeof(struct android_app)); - android_app->activity = activity; - - pthread_mutex_init(&android_app->mutex, NULL); - pthread_cond_init(&android_app->cond, NULL); - - if (savedState != NULL) { - android_app->savedState = malloc(savedStateSize); - android_app->savedStateSize = savedStateSize; - memcpy(android_app->savedState, savedState, savedStateSize); - } - - int msgpipe[2]; - if (pipe(msgpipe)) { - LOGE("could not create pipe: %s", strerror(errno)); - return NULL; - } - android_app->msgread = msgpipe[0]; - android_app->msgwrite = msgpipe[1]; - - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - pthread_create(&android_app->thread, &attr, android_app_entry, android_app); - - // Дождитесь запуска потока. - pthread_mutex_lock(&android_app->mutex); - while (!android_app->running) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - pthread_mutex_unlock(&android_app->mutex); - - return android_app; -} - -static void android_app_write_cmd(struct android_app* android_app, int8_t cmd) { - if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) { - LOGE("Failure writing android_app cmd: %s\n", strerror(errno)); - } -} - -static void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) { - pthread_mutex_lock(&android_app->mutex); - android_app->pendingInputQueue = inputQueue; - android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED); - while (android_app->inputQueue != android_app->pendingInputQueue) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - pthread_mutex_unlock(&android_app->mutex); -} - -static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) { - pthread_mutex_lock(&android_app->mutex); - if (android_app->pendingWindow != NULL) { - android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW); - } - android_app->pendingWindow = window; - if (window != NULL) { - android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW); - } - while (android_app->window != android_app->pendingWindow) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - pthread_mutex_unlock(&android_app->mutex); -} - -static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) { - pthread_mutex_lock(&android_app->mutex); - android_app_write_cmd(android_app, cmd); - while (android_app->activityState != cmd) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - pthread_mutex_unlock(&android_app->mutex); -} - -static void android_app_free(struct android_app* android_app) { - pthread_mutex_lock(&android_app->mutex); - android_app_write_cmd(android_app, APP_CMD_DESTROY); - while (!android_app->destroyed) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - pthread_mutex_unlock(&android_app->mutex); - - close(android_app->msgread); - close(android_app->msgwrite); - pthread_cond_destroy(&android_app->cond); - pthread_mutex_destroy(&android_app->mutex); - free(android_app); -} - -static void onDestroy(ANativeActivity* activity) { - LOGV("Destroy: %p\n", activity); - android_app_free((struct android_app*)activity->instance); -} - -static void onStart(ANativeActivity* activity) { - LOGV("Start: %p\n", activity); - android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START); -} - -static void onResume(ANativeActivity* activity) { - LOGV("Resume: %p\n", activity); - android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME); -} - -static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) { - struct android_app* android_app = (struct android_app*)activity->instance; - void* savedState = NULL; - - LOGV("SaveInstanceState: %p\n", activity); - pthread_mutex_lock(&android_app->mutex); - android_app->stateSaved = 0; - android_app_write_cmd(android_app, APP_CMD_SAVE_STATE); - while (!android_app->stateSaved) { - pthread_cond_wait(&android_app->cond, &android_app->mutex); - } - - if (android_app->savedState != NULL) { - savedState = android_app->savedState; - *outLen = android_app->savedStateSize; - android_app->savedState = NULL; - android_app->savedStateSize = 0; - } - - pthread_mutex_unlock(&android_app->mutex); - - return savedState; -} - -static void onPause(ANativeActivity* activity) { - LOGV("Pause: %p\n", activity); - android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE); -} - -static void onStop(ANativeActivity* activity) { - LOGV("Stop: %p\n", activity); - android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP); -} - -static void onConfigurationChanged(ANativeActivity* activity) { - struct android_app* android_app = (struct android_app*)activity->instance; - LOGV("ConfigurationChanged: %p\n", activity); - android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED); -} - -static void onLowMemory(ANativeActivity* activity) { - struct android_app* android_app = (struct android_app*)activity->instance; - LOGV("LowMemory: %p\n", activity); - android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY); -} - -static void onWindowFocusChanged(ANativeActivity* activity, int focused) { - LOGV("WindowFocusChanged: %p -- %d\n", activity, focused); - android_app_write_cmd((struct android_app*)activity->instance, - focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS); -} - -static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) { - LOGV("NativeWindowCreated: %p -- %p\n", activity, window); - android_app_set_window((struct android_app*)activity->instance, window); -} - -static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) { - LOGV("NativeWindowDestroyed: %p -- %p\n", activity, window); - android_app_set_window((struct android_app*)activity->instance, NULL); -} - -static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) { - LOGV("InputQueueCreated: %p -- %p\n", activity, queue); - android_app_set_input((struct android_app*)activity->instance, queue); -} - -static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) { - LOGV("InputQueueDestroyed: %p -- %p\n", activity, queue); - android_app_set_input((struct android_app*)activity->instance, NULL); -} - -void ANativeActivity_onCreate(ANativeActivity* activity, - void* savedState, size_t savedStateSize) { - LOGV("Creating: %p\n", activity); - activity->callbacks->onDestroy = onDestroy; - activity->callbacks->onStart = onStart; - activity->callbacks->onResume = onResume; - activity->callbacks->onSaveInstanceState = onSaveInstanceState; - activity->callbacks->onPause = onPause; - activity->callbacks->onStop = onStop; - activity->callbacks->onConfigurationChanged = onConfigurationChanged; - activity->callbacks->onLowMemory = onLowMemory; - activity->callbacks->onWindowFocusChanged = onWindowFocusChanged; - activity->callbacks->onNativeWindowCreated = onNativeWindowCreated; - activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed; - activity->callbacks->onInputQueueCreated = onInputQueueCreated; - activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed; - - activity->instance = android_app_create(activity, savedState, savedStateSize); -} diff --git a/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/android_native_app_glue.h b/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/android_native_app_glue.h deleted file mode 100644 index c7269a444..000000000 --- a/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/android_native_app_glue.h +++ /dev/null @@ -1,344 +0,0 @@ -/* - * © 2010 The Android Open Source Project - * - * Лицензировано по лицензии Apache License, версия 2.0 ( "Лицензия"); - *этот файл можно использовать только в соответствии с лицензией. - *Копию лицензии можно получить на веб-сайте - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - *Если только не требуется в соответствии с применимым законодательством или согласовано в письменном виде, программное обеспечение - * распространяется в рамках лицензии на УСЛОВИЯХ "КАК ЕСТЬ", - * БЕЗ ГАРАНТИЙ И УСЛОВИЙ ЛЮБОГО РОДА, явно выраженных и подразумеваемых. - * См. лицензию для получения информации об определенных разрешениях по использованию языка и - * ограничениях в рамках лицензии. - * - */ - -#ifndef _ANDROID_NATIVE_APP_GLUE_H -#define _ANDROID_NATIVE_APP_GLUE_H - -#include -#include -#include - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Интерфейс NativeActivity, предоставленный , - * основан на наборе предоставленных приложением обратных вызовов, которые вызываются - *основным потоком действия при возникновении определенных событий. - * - * Это означает, что ни один из данных обратных вызовов _не_ _должен_ блокироваться, иначе - * существует риск принудительного закрытия приложения системой. Эта модель программирования - * прямая, простая, но имеет ограничения. - * - * Статическая библиотека threaded_native_app используется для обеспечения другой - * модели выполнения, в которой приложение может реализовать свой собственный цикл главного события - * в другом потоке вместо этого. Это работает так: - * - * 1/ Приложение должно предоставить функцию с именем android_main(), которая - * будет вызываться при создании действия в новом потоке, - * отличающемся от основного потока действия. - * - * 2/ android_main() получает указатель на допустимую структуру android_app, - * которая содержит ссылки на другие важные объекты, например экземпляр объекта - * ANativeActivity, где выполняется приложение. - * - * 3/ Объект android_app содержит экземпляр ALooper, который уже - * ожидает две важных вещи: - * - * - событий жизненного цикла действия (например, "pause", "resume"). См. объявления APP_CMD_XXX - * ниже. - * - * - входных событий, поступающих из очереди AInputQueue, присоединенной к действию. - * - * Каждое из этих событий соответствует идентификатору ALooper, возвращенному - * ALooper_pollOnce со значениями LOOPER_ID_MAIN и LOOPER_ID_INPUT, - *, соответственно. - * - * Ваше приложение может использовать тот же ALooper для прослушивания дополнительных - * дескрипторов файла. Они могут быть основаны либо на обратных вызовах, либо поступают с идентификаторами возврата, - * начинающимися с LOOPER_ID_USER. - * - * 4/ При получении события LOOPER_ID_MAIN или LOOPER_ID_INPUT - * возвращенные данные будут указывать на структуру android_poll_source. Для нее - * можно вызвать функцию process() и заполнить android_app->onAppCmd - * и android_app->onInputEvent, для того чтобы они вызывались для вашей собственной обработки - * события. - * - * Вместо этого можно вызвать функции нижнего уровня для чтения и обработки - * данных непосредственно... посмотрите на реализации process_cmd() и process_input() - * в приклеивании, чтобы выяснить, как это делается. - * - * См. пример "native-activity" в NDK с - * полной демонстрацией использования. Также посмотрите JavaDoc в NativeActivity. - */ - -struct android_app; - -/** - * Данные, связанные с ALooper fd, которые будут возвращаться как outData - * при готовности данных в этом источнике. - */ -struct android_poll_source { - // Идентификатор данного источника. Может быть LOOPER_ID_MAIN или - // LOOPER_ID_INPUT. - int32_t id; - - // android_app, с которым связан данный идентификатор. - struct android_app* app; - - // Функция, вызываемая для стандартной обработки данных из - // этого источника. - void (*process)(struct android_app* app, struct android_poll_source* source); -}; - -/** - * Это интерфейс стандартного кода приклеивания поточного - * приложения. В этой модели код приложения выполняется - * в своем собственном потоке, отдельном от основного потока процесса. - * Не требуется связь данного потока с ВМ Java - *, хотя это необходимо для выполнения вызовов JNI любых - * объектов Java. - */ -struct android_app { - // Приложение может поместить указатель на свой собственный объект состояния - // здесь, если нужно. - void* userData; - - // Введите здесь код функции для обработки основных команд приложения (APP_CMD_*) - void (*onAppCmd)(struct android_app* app, int32_t cmd); - - // Введите здесь код функции для обработки входных событий. Сейчас - // событие уже было предварительно отправлено и будет завершено при - // возврате. Верните 1, если событие обработано, 0 — для любой диспетчеризации - // по умолчанию. - int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event); - - // Экземпляр объекта ANativeActivity, в котором выполняется это приложение. - ANativeActivity* activity; - - // Текущая конфигурация, в которой выполняется это приложение. - AConfiguration* config; - - // Это последнее сохраненное состояние экземпляра, предоставленное во время создания. - // Значение равно NULL, если состояния не было. Можно использовать это по мере необходимости; - // память останется доступной до вызова android_app_exec_cmd() для - // APP_CMD_RESUME, после чего она будет освобождена, а savedState получит значение NULL. - // Эти переменные необходимо изменять только при обработке APP_CMD_SAVE_STATE, - // когда их значения будут инициализироваться в NULL и можно будет выполнить malloc для - // состояния и поместить здесь информацию. В этом случае память будет - // освобождена позднее. - void* savedState; - size_t savedStateSize; - - // ALooper, связанный с потоком приложения. - ALooper* looper; - - // Если значение не равно NULL, то это входная очередь, из которой приложение будет - // получать входные события пользователя. - AInputQueue* inputQueue; - - // Если значение не равно NULL, то это поверхность окна, в котором приложение может рисовать. - ANativeWindow* window; - - // Текущий прямоугольник содержимого окна. Это область, в которой - // должно помещаться содержимое окна, чтобы его видел пользователь. - ARect contentRect; - - // Текущее состояние действия приложения. Может быть APP_CMD_START, - // APP_CMD_RESUME, APP_CMD_PAUSE или APP_CMD_STOP; см. ниже. - int activityState; - - // Значение не равно нулю, когда NativeActivity приложения - // разрушается и ожидает завершения потока приложения. - int destroyRequested; - - // ------------------------------------------------- - // Ниже показан "частная" реализация кода прилипания. - - pthread_mutex_t mutex; - pthread_cond_t cond; - - int msgread; - int msgwrite; - - pthread_t thread; - - struct android_poll_source cmdPollSource; - struct android_poll_source inputPollSource; - - int running; - int stateSaved; - int destroyed; - int redrawNeeded; - AInputQueue* pendingInputQueue; - ANativeWindow* pendingWindow; - ARect pendingContentRect; -}; - -enum { - /** - * Идентификатор данных Looper команд, поступающих из основного потока приложения, который - * возвращается как идентификатор от ALooper_pollOnce(). Данные для этого идентификатора - * являются указателем на структуру android_poll_source. - * Их можно извлечь и обработать с помощью android_app_read_cmd() - * и android_app_exec_cmd(). - */ - LOOPER_ID_MAIN = 1, - - /** - * Идентификатор данных Looper событий, поступающий из AInputQueue окна - * приложения, который возвращается как идентификатор из - * ALooper_pollOnce(). Данные этого идентификатора являются указателем на структуру - * android_poll_source. Их можно прочитать через объект inputQueue - * приложения android_app. - */ - LOOPER_ID_INPUT = 2, - - /** - * Запуск определяемых пользователем идентификаторов ALooper. - */ - LOOPER_ID_USER = 3, -}; - -enum { - /** - * Команда из основного потока: AInputQueue изменена. После обработки - * этой команды android_app->inputQueue будет обновлена в новую очередь - * (или NULL). - */ - APP_CMD_INPUT_CHANGED, - - /** - * Команда из основного потока: новое окно ANativeWindow готово к использованию. После - * получения этой команды окно android_app-> будет содержать новую поверхность - *окна. - */ - APP_CMD_INIT_WINDOW, - - /** - * Команда из основного потока: существующее окно ANativeWindow необходимо - * прекратить. После получения этой команды окно android_app->по-прежнему - * содержит существующее окно; после вызова android_app_exec_cmd - * оно получит значение NULL. - */ - APP_CMD_TERM_WINDOW, - - /** - * Команда из основного потока: текущее окно ANativeWindow изменило размер. - * Перерисуйте согласно новом размеру. - */ - APP_CMD_WINDOW_RESIZED, - - /** - * Команда из основного потока: системе необходимо, чтобы текущее окно ANativeWindow - * было перерисовано. Необходимо перерисовать окно перед ее передачей в - * android_app_exec_cmd(), чтобы избежать переходных сбоев рисования. - */ - APP_CMD_WINDOW_REDRAW_NEEDED, - - /** - * Команда из основного потока: область содержимого окна изменена - * таким образом, что из функционального ввода окно показывается или скрывается. Можно - * найти новый прямоугольник содержимого в android_app::contentRect. - */ - APP_CMD_CONTENT_RECT_CHANGED, - - /** - * Команда из основного потока: окно действия приложения получило - * фокус ввода. - */ - APP_CMD_GAINED_FOCUS, - - /** - * Команда из основного потока: окно действия приложения потеряло - * фокус ввода. - */ - APP_CMD_LOST_FOCUS, - - /** - * Команда из основного потока: изменена текущая конфигурация устройства. - */ - APP_CMD_CONFIG_CHANGED, - - /** - * Команда из основного потока: системе не хватает памяти. - * Попробуйте уменьшить использование памяти. - */ - APP_CMD_LOW_MEMORY, - - /** - * Команда из основного потока: действие приложения было запущено. - */ - APP_CMD_START, - - /** - * Команда из основного потока: действие приложения было возобновлено. - */ - APP_CMD_RESUME, - - /** - * Команда из основного потока: приложение должно создать новое сохраненное состояние - * для себя, чтобы восстанавливаться из него позднее в случае необходимости. Если вы сохранили состояние, - * выделите его с использованием malloc и поместите в android_app.savedState с - * размером android_app.savedStateSize. Память будет освобождена - * позднее. - */ - APP_CMD_SAVE_STATE, - - /** - * Команда из основного потока: пауза в действии приложения. - */ - APP_CMD_PAUSE, - - /** - * Команда из основного потока: действие приложения было остановлено. - */ - APP_CMD_STOP, - - /** - * Команда из основного потока: действие приложения уничтожается, - * и ожидает очистки потока приложения и выхода перед обработкой. - */ - APP_CMD_DESTROY, -}; - -/** - * Вызовите, когда ALooper_pollAll() возвращает LOOPER_ID_MAIN, при чтении следующего сообщения команды - *приложения. - */ -int8_t android_app_read_cmd(struct android_app* android_app); - -/** - * Вызовите с помощью команды, возвращенной android_app_read_cmd() для выполнения - * начальной предварительной обработки данной команды. Можно выполнить собственные - * действия для команды после вызова этой функции. - */ -void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd); - -/** - * Вызовите с помощью команды, возвращенной android_app_read_cmd(), для - * окончательной предварительной обработки данной команды. Необходимо завершить собственные - * действия с командой до вызова этой функции. - */ -void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd); - -/** - * Это функция, которую должен реализовать код приложения, представляет собой - * главный вход в приложение. - */ -extern void android_main(struct android_app* app); - -#ifdef __cplusplus -} -#endif - -#endif /* _ANDROID_NATIVE_APP_GLUE_H */ diff --git a/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/main.c b/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/main.c deleted file mode 100644 index dce3f503c..000000000 --- a/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/main.c +++ /dev/null @@ -1,64 +0,0 @@ -/******************************************************************************************* -* -* raylib [core] example - Basic window -* -* This example has been created using raylib 3.8 (www.raylib.com) -* raylib is licensed under an unmodified zlib/libpng license (View raylib.h for details) -* -* Example contributed by (@) and reviewed by Ramon Santamaria (@raysan5) -* -* Copyright (c) 2021 (@) - -* Adapt for Visual Studio: Vadim Boev (Kronka Dev) -* -********************************************************************************************/ -#include "android_native_app_glue.h" - -#include "../../../../src/raylib.h" - -int main(void) -{ - // Initialization - //-------------------------------------------------------------------------------------- - const int screenWidth = 800; - const int screenHeight = 450; - - InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window"); - - // TODO: Load resources / Initialize variables at this point - - SetTargetFPS(60); - //-------------------------------------------------------------------------------------- - - // Main game loop - while (!WindowShouldClose()) // Detect window close button or ESC key - { - // Update - //---------------------------------------------------------------------------------- - // TODO: Update variables / Implement example logic at this point - //---------------------------------------------------------------------------------- - - // Draw - //---------------------------------------------------------------------------------- - BeginDrawing(); - - ClearBackground(RAYWHITE); - - // TODO: Draw everything that requires to be drawn at this point: - - DrawText("Congrats! You created your first window!", 190, 200, 20, LIGHTGRAY); // Example - - EndDrawing(); - //---------------------------------------------------------------------------------- - } - - // De-Initialization - //-------------------------------------------------------------------------------------- - - // TODO: Unload all loaded resources at this point - - CloseWindow(); // Close window and OpenGL context - //-------------------------------------------------------------------------------------- - - return 0; -} diff --git a/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/raylib_android.NativeActivity.vcxproj b/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/raylib_android.NativeActivity.vcxproj deleted file mode 100644 index 6b7b5a085..000000000 --- a/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/raylib_android.NativeActivity.vcxproj +++ /dev/null @@ -1,226 +0,0 @@ - - - - - Debug - ARM - - - Release - ARM - - - Debug - ARM64 - - - Release - ARM64 - - - Debug - x64 - - - Release - x64 - - - Debug - x86 - - - Release - x86 - - - - {bfb31759-4fca-4503-bc7c-a97f705efdb2} - Android - raylib_android - en-US - 14.0 - Android - 3.0 - - - - DynamicLibrary - true - Clang_5_0 - - - DynamicLibrary - false - Clang_5_0 - - - DynamicLibrary - true - Clang_5_0 - - - DynamicLibrary - false - Clang_5_0 - - - DynamicLibrary - true - Clang_5_0 - android-29 - - - DynamicLibrary - false - Clang_5_0 - - - DynamicLibrary - true - Clang_5_0 - - - DynamicLibrary - false - Clang_5_0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - libmain - - - - - - - - - - - NotUsing - pch.h - CompileAsC - c99 - Default - CompileAsC - - - %(LibraryDependencies);EGL;GLESv2;log;android;c;m;raylib - ../../../../src/;%(AdditionalLibraryDirectories) - - - - - NotUsing - pch.h - CompileAsC - c99 - Default - CompileAsC - - - %(LibraryDependencies);GLESv1_CM;EGL; - .;%(AdditionalLibraryDirectories) - - - - - Use - pch.h - CompileAsCpp - - - %(LibraryDependencies);GLESv1_CM;EGL; - - - - - Use - pch.h - CompileAsCpp - - - %(LibraryDependencies);GLESv1_CM;EGL; - - - - - Use - pch.h - CompileAsCpp - - - %(LibraryDependencies);GLESv1_CM;EGL; - - - - - Use - pch.h - CompileAsCpp - - - %(LibraryDependencies);GLESv1_CM;EGL; - - - - - Use - pch.h - CompileAsCpp - - - %(LibraryDependencies);GLESv1_CM;EGL; - - - - - Use - pch.h - CompileAsCpp - - - %(LibraryDependencies);GLESv1_CM;EGL; - - - - - - - - - - - - - \ No newline at end of file diff --git a/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/raylib_android.NativeActivity.vcxproj.filters b/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/raylib_android.NativeActivity.vcxproj.filters deleted file mode 100644 index e9a26e2dd..000000000 --- a/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/raylib_android.NativeActivity.vcxproj.filters +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/raylib_android.NativeActivity.vcxproj.user b/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/raylib_android.NativeActivity.vcxproj.user deleted file mode 100644 index 0f14913f3..000000000 --- a/projects/VS2019-Android/raylib_android/raylib_android.NativeActivity/raylib_android.NativeActivity.vcxproj.user +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/projects/VS2019-Android/raylib_android/raylib_android.Packaging/AndroidManifest.xml b/projects/VS2019-Android/raylib_android/raylib_android.Packaging/AndroidManifest.xml deleted file mode 100644 index 8d58d3756..000000000 --- a/projects/VS2019-Android/raylib_android/raylib_android.Packaging/AndroidManifest.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/projects/VS2019-Android/raylib_android/raylib_android.Packaging/build.xml b/projects/VS2019-Android/raylib_android/raylib_android.Packaging/build.xml deleted file mode 100644 index 4dd78480d..000000000 --- a/projects/VS2019-Android/raylib_android/raylib_android.Packaging/build.xml +++ /dev/null @@ -1,90 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/projects/VS2019-Android/raylib_android/raylib_android.Packaging/project.properties b/projects/VS2019-Android/raylib_android/raylib_android.Packaging/project.properties deleted file mode 100644 index 3c100376c..000000000 --- a/projects/VS2019-Android/raylib_android/raylib_android.Packaging/project.properties +++ /dev/null @@ -1,3 +0,0 @@ -# Project target -target=$(androidapilevel) -# Provide path to the directory where prebuilt external jar files are by setting jar.libs.dir= diff --git a/projects/VS2019-Android/raylib_android/raylib_android.Packaging/raylib_android.Packaging.androidproj b/projects/VS2019-Android/raylib_android/raylib_android.Packaging/raylib_android.Packaging.androidproj deleted file mode 100644 index 030d71747..000000000 --- a/projects/VS2019-Android/raylib_android/raylib_android.Packaging/raylib_android.Packaging.androidproj +++ /dev/null @@ -1,134 +0,0 @@ - - - - - Debug - ARM - - - Release - ARM - - - Debug - ARM64 - - - Release - ARM64 - - - Debug - x64 - - - Release - x64 - - - Debug - x86 - - - Release - x86 - - - - raylib_android - 14.0 - 1.0 - {b2231f0d-52da-4c55-8998-5886f766553c} - - - - true - Application - - - false - Application - - - true - Application - - - false - Application - - - true - Application - - - false - Application - - - true - Application - - - false - Application - - - - - - - - - $(RootNamespace) - - - - - $(RootNamespace) - - - - - $(RootNamespace) - - - - - $(RootNamespace) - - - - - $(RootNamespace) - - - - - $(RootNamespace) - - - - - $(RootNamespace) - - - - - $(RootNamespace) - - - - - - - - - - - {bfb31759-4fca-4503-bc7c-a97f705efdb2} - - - - - \ No newline at end of file diff --git a/projects/VS2019-Android/raylib_android/raylib_android.Packaging/res/values/strings.xml b/projects/VS2019-Android/raylib_android/raylib_android.Packaging/res/values/strings.xml deleted file mode 100644 index 98afc4675..000000000 --- a/projects/VS2019-Android/raylib_android/raylib_android.Packaging/res/values/strings.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - raylib_android.Packaging - From 66bb527d222aa93d16f9df78e01bb2818f832825 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 16 Jul 2026 15:10:46 +0200 Subject: [PATCH 69/94] Update README.md --- projects/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/projects/README.md b/projects/README.md index 27196b93a..b1f48cdf2 100644 --- a/projects/README.md +++ b/projects/README.md @@ -4,7 +4,6 @@ This folder contains raylib templates for some common IDEs. IDE | Platform(s) | Source | Example(s) ----| ------------| :-------: | :-----: -[4coder](http://4coder.net/) | Windows | ❌ | ✔️ [Builder](https://wiki.gnome.org/Apps/Builder) | Linux | ❌ | ✔️ [CMake](https://cmake.org/) | Windows, Linux, macOS, Web | ✔️ | ✔️ [CodeBlocks](http://www.codeblocks.org/) | Windows, Linux, macOS | ❌ | ✔️ From 7aceceb4670c5cce87bd42133f444371875b4f63 Mon Sep 17 00:00:00 2001 From: GideonSerf Date: Fri, 17 Jul 2026 20:31:26 +0200 Subject: [PATCH 70/94] Fix logging format for automation event capacity warning (#5986) Co-authored-by: gideons --- src/rcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rcore.c b/src/rcore.c index 0bf8a5760..a368cabec 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -3608,7 +3608,7 @@ AutomationEventList LoadAutomationEventList(const char *fileName) counter++; } - else TRACELOG(LOG_WARNING, "AUTOMATION: Event goes beyond automated list capacity (MAX: %i): %s", buffer, list.capacity); + else TRACELOG(LOG_WARNING, "AUTOMATION: Event goes beyond automated list capacity (MAX: %u): %s", list.capacity, buffer); } break; default: break; } From aa088e42d15994c2a5b4fc219e258bfe5531b03f Mon Sep 17 00:00:00 2001 From: meta-legend <110937181+meta-legend@users.noreply.github.com> Date: Fri, 17 Jul 2026 16:12:57 -0500 Subject: [PATCH 71/94] fix static link deps (#5990) --- src/CMakeLists.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 55428e882..bdf3207f3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -107,6 +107,20 @@ endif () target_link_libraries(raylib PRIVATE $) target_link_libraries(raylib PUBLIC ${LIBS_PUBLIC}) +# Static libraries must export their private link dependencies for installed consumers. +# LINK_ONLY keeps those dependencies out of the compile interface. +if (NOT BUILD_SHARED_LIBS) + set(raylib_install_private_libs ${LIBS_PRIVATE}) + + if (NOT glfw3_FOUND) + list(REMOVE_ITEM raylib_install_private_libs glfw) + endif() + + foreach(lib IN LISTS raylib_install_private_libs) + target_link_libraries(raylib INTERFACE $>) + endforeach() +endif() + # Sets some compile time definitions for the pre-processor # If CUSTOMIZE_BUILD option is on you will not use config.h by default # and you will be able to select more build options From 5b1445b38195b739faaa9e211be2bd272bb77f00 Mon Sep 17 00:00:00 2001 From: Mierenik <110776142+gummyniki@users.noreply.github.com> Date: Sat, 18 Jul 2026 00:22:35 +0300 Subject: [PATCH 72/94] FIXED: ImageFromImage() heap-buffer-overflow on compressed formats (#5991) --- src/rtextures.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/rtextures.c b/src/rtextures.c index 61e528d47..afc69f166 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -1230,23 +1230,31 @@ Image ImageFromImage(Image image, Rectangle rec) { Image result = { 0 }; + // Security check to avoid program crash + if ((image.data == NULL) || (image.width == 0) || (image.height == 0)) return result; + // Basic rectangle validation: size smaller than image size if ((rec.x >= 0) && (rec.y >= 0) && (rec.width > 0) && (rec.height > 0) && (((int)rec.x + (int)rec.width) <= image.width) && (((int)rec.y + (int)rec.height) <= image.height)) { - int bytesPerPixel = GetPixelDataSize(1, 1, image.format); - result.width = (int)rec.width; - result.height = (int)rec.height; - result.data = RL_CALLOC((int)rec.width*(int)rec.height*bytesPerPixel, 1); - result.format = image.format; - result.mipmaps = 1; + if (image.format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "IMAGE: Image manipulation not supported for compressed formats"); + else + { + int bytesPerPixel = GetPixelDataSize(1, 1, image.format); - for (int y = 0; y < (int)rec.height; y++) - { - memcpy(((unsigned char *)result.data) + y*(int)rec.width*bytesPerPixel, ((unsigned char *)image.data) + ((y + (int)rec.y)*image.width + (int)rec.x)*bytesPerPixel, (int)rec.width*bytesPerPixel); - } + result.width = (int)rec.width; + result.height = (int)rec.height; + result.data = RL_CALLOC((int)rec.width*(int)rec.height*bytesPerPixel, 1); + result.format = image.format; + result.mipmaps = 1; + + for (int y = 0; y < (int)rec.height; y++) + { + memcpy(((unsigned char *)result.data) + y*(int)rec.width*bytesPerPixel, ((unsigned char *)image.data) + ((y + (int)rec.y)*image.width + (int)rec.x)*bytesPerPixel, (int)rec.width*bytesPerPixel); + } + } } else TRACELOG(LOG_WARNING, "IMAGE: Rectangle provided for ImageToImage not valid"); From 0725811224e9452cf7984d9874b5113a0acef8bd Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 18 Jul 2026 16:43:04 +0200 Subject: [PATCH 73/94] Added a note reminder --- src/rlgl.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/rlgl.h b/src/rlgl.h index 68eec7fdf..7f3fe54cd 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -3793,6 +3793,10 @@ unsigned char *rlReadScreenPixels(int width, int height) { unsigned char *imgData = (unsigned char *)RL_CALLOC(width*height*4, sizeof(unsigned char)); + // NOTE: Buffer retrieved is GL_FRONT in single-buffered configurations + // and GL_BACK in double-buffered configurations, make sure to call it at the end of frame + //glReadBuffer(GL_BACK); + // NOTE: glReadPixels() returns image flipped vertically -> (0,0) is the bottom left corner of the framebuffer // WARNING: Getting alpha channel! Be careful, it can be transparent if not cleared properly! glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, imgData); From b806e3d2ecd72c1b1fcfb60bf8cdc982859fc32e Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 18 Jul 2026 16:44:10 +0200 Subject: [PATCH 74/94] Replaced comments text `given` by `provided` --- src/raylib.h | 14 +++++++------- src/rcore.c | 10 +++++----- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index f0e67f535..e7c449d84 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1154,14 +1154,14 @@ RLAPI long GetFileModTime(const char *fileName); // Get file RLAPI const char *GetFileExtension(const char *fileName); // Get pointer to extension for a filename string (includes dot: '.png') RLAPI const char *GetFileName(const char *filePath); // Get pointer to filename for a path string RLAPI const char *GetFileNameWithoutExt(const char *filePath); // Get filename string without extension (uses static string) -RLAPI const char *GetDirectoryPath(const char *filePath); // Get full path for a given fileName with path (uses static string) -RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previous directory path for a given path (uses static string) +RLAPI const char *GetDirectoryPath(const char *filePath); // Get full path for a provided fileName with path (uses static string) +RLAPI const char *GetPrevDirectoryPath(const char *dirPath); // Get previous directory path for a provided path (uses static string) RLAPI const char *GetWorkingDirectory(void); // Get current working directory (uses static string) RLAPI const char *GetApplicationDirectory(void); // Get the directory of the running application (uses static string) RLAPI int MakeDirectory(const char *dirPath); // Create directories (including full path requested), returns 0 on success RLAPI int ChangeDirectory(const char *dirPath); // Change working directory, returns 0 on success -RLAPI bool IsPathFile(const char *path); // Check if given path points to a file -RLAPI bool IsPathDirectory(const char *path); // Check if given path points to a directory +RLAPI bool IsPathFile(const char *path); // Check if provided path points to a file +RLAPI bool IsPathDirectory(const char *path); // Check if provided path points to a directory RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths, files and directories, no subdirs scan RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and subdir scan; some filters available: '*.*','FILES*','DIRS*' @@ -1240,7 +1240,7 @@ RLAPI void SetMouseCursor(int cursor); // Set mouse curso RLAPI int GetTouchX(void); // Get touch position X for touch point 0 (relative to screen size) RLAPI int GetTouchY(void); // Get touch position Y for touch point 0 (relative to screen size) RLAPI Vector2 GetTouchPosition(int index); // Get touch position XY for a touch point index (relative to screen size) -RLAPI int GetTouchPointId(int index); // Get touch point identifier for given index +RLAPI int GetTouchPointId(int index); // Get touch point identifier for provided index RLAPI int GetTouchPointCount(void); // Get number of touch points //------------------------------------------------------------------------------------ @@ -1327,7 +1327,7 @@ RLAPI void DrawSplineSegmentCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vecto RLAPI void DrawSplineSegmentBezierQuadratic(Vector2 p1, Vector2 c2, Vector2 p3, float thick, Color color); // Draw spline segment: Quadratic Bezier, 2 points, 1 control point RLAPI void DrawSplineSegmentBezierCubic(Vector2 p1, Vector2 c2, Vector2 c3, Vector2 p4, float thick, Color color); // Draw spline segment: Cubic Bezier, 2 points, 2 control points -// Spline segment point evaluation functions, for a given t [0.0f .. 1.0f] +// Spline segment point evaluation functions, for a provided t [0.0f .. 1.0f] RLAPI Vector2 GetSplinePointLinear(Vector2 startPos, Vector2 endPos, float t); // Get (evaluate) spline point: Linear RLAPI Vector2 GetSplinePointBasis(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t); // Get (evaluate) spline point: B-Spline RLAPI Vector2 GetSplinePointCatmullRom(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, float t); // Get (evaluate) spline point: Catmull-Rom @@ -1417,7 +1417,7 @@ RLAPI Color GetImageColor(Image image, int x, int y); // Image drawing functions // NOTE: Image software-rendering functions (CPU) -RLAPI void ImageClearBackground(Image *dst, Color color); // Clear image background with given color +RLAPI void ImageClearBackground(Image *dst, Color color); // Clear image background with provided color RLAPI void ImageDrawPixel(Image *dst, int posX, int posY, Color color); // Draw pixel within an image RLAPI void ImageDrawPixelV(Image *dst, Vector2 position, Color color); // Draw pixel within an image (Vector version) RLAPI void ImageDrawLine(Image *dst, int startPosX, int startPosY, int endPosX, int endPosY, Color color); // Draw line within an image diff --git a/src/rcore.c b/src/rcore.c index a368cabec..b6cfeaabb 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -2522,7 +2522,7 @@ const char *GetFileNameWithoutExt(const char *filePath) return fileName; } -// Get directory for a given filePath +// Get directory for a provided filePath const char *GetDirectoryPath(const char *filePath) { /* @@ -2569,7 +2569,7 @@ const char *GetDirectoryPath(const char *filePath) return dirPath; } -// Get previous directory path for a given path +// Get previous directory path for a provided path const char *GetPrevDirectoryPath(const char *dirPath) { static char prevDirPath[MAX_FILEPATH_LENGTH] = { 0 }; @@ -2819,7 +2819,7 @@ int ChangeDirectory(const char *dirPath) return result; } -// Check if given path point to a file +// Check if provided path point to a file bool IsPathFile(const char *path) { bool result = false; @@ -2832,7 +2832,7 @@ bool IsPathFile(const char *path) return result; } -// Check if given path point to a directory +// Check if provided path point to a directory bool IsPathDirectory(const char *path) { bool result = false; @@ -4214,7 +4214,7 @@ Vector2 GetTouchPosition(int index) return position; } -// Get touch point identifier for given index +// Get touch point identifier for provided index int GetTouchPointId(int index) { int id = -1; From cfccb83ddd38395015bc1caca6e845ff713ff90f Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 18 Jul 2026 16:44:41 +0200 Subject: [PATCH 75/94] ADDED: `IsPathAbsolute()` to check absolute paths --- src/raylib.h | 1 + src/rcore.c | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/raylib.h b/src/raylib.h index e7c449d84..154158131 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -1162,6 +1162,7 @@ RLAPI int MakeDirectory(const char *dirPath); // Create di RLAPI int ChangeDirectory(const char *dirPath); // Change working directory, returns 0 on success RLAPI bool IsPathFile(const char *path); // Check if provided path points to a file RLAPI bool IsPathDirectory(const char *path); // Check if provided path points to a directory +RLAPI bool IsPathAbsolute(const char *path); // Check if provided path is an absolute path RLAPI bool IsFileNameValid(const char *fileName); // Check if fileName is valid for the platform/OS RLAPI FilePathList LoadDirectoryFiles(const char *dirPath); // Load directory filepaths, files and directories, no subdirs scan RLAPI FilePathList LoadDirectoryFilesEx(const char *basePath, const char *filter, bool scanSubdirs); // Load directory filepaths with extension filtering and subdir scan; some filters available: '*.*','FILES*','DIRS*' diff --git a/src/rcore.c b/src/rcore.c index b6cfeaabb..80d1cbf11 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -2842,6 +2842,28 @@ bool IsPathDirectory(const char *path) return result; } +// Check if provided path is an absolute path +static bool IsPathAbsolute(const char *path) +{ + int result = false; + + if ((path != NULL) && (path[0] != '\0')) + { +#if defined(_WIN32) + // UNC path (\\server\share) + if ((path[0] == '\\') && (path[1] == '\\')) result = true; + // Drive letter (e.g. C:\ or D:/) + else if (isalpha((unsigned char)path[0]) && (path[1] == ':') && + ((path[2] == '\\') || (path[2] == '/'))) result = true; +#else + // POSIX: must start with / + if (path[0] == '/') result = true; +#endif + } + + return result; +} + // Check if fileName is valid for the platform/OS bool IsFileNameValid(const char *fileName) { From 58e03dbc6cec4d14b2f4299d4df0eacf58fc5d78 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 18 Jul 2026 16:45:28 +0200 Subject: [PATCH 76/94] REVIEWED: `TakeScreenshot()` to support absolute paths --- src/rcore.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 80d1cbf11..ec4d8a473 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -1804,7 +1804,6 @@ void UnloadRandomSequence(int *sequence) } // Takes a screenshot of current screen -// NOTE: Provided fileName should not contain paths, saving to working directory void TakeScreenshot(const char *fileName) { #if SUPPORT_MODULE_RTEXTURES @@ -1819,7 +1818,8 @@ void TakeScreenshot(const char *fileName) Image image = { imgData, (int)((float)CORE.Window.render.width*scale.x), (int)((float)CORE.Window.render.height*scale.y), 1, PIXELFORMAT_UNCOMPRESSED_R8G8B8A8 }; char path[MAX_FILEPATH_LENGTH] = { 0 }; - snprintf(path, MAX_FILEPATH_LENGTH, "%s", TextFormat("%s/%s", CORE.Storage.basePath, fileName)); + if (!IsPathAbsolute(fileName)) snprintf(path, MAX_FILEPATH_LENGTH, "%s", TextFormat("%s/%s", CORE.Storage.basePath, fileName)); + else snprintf(path, MAX_FILEPATH_LENGTH, "%s", fileName); ExportImage(image, path); // WARNING: Module required: rtextures RL_FREE(imgData); From baa9a4df514a6701c79b8fd04f69187de82c0200 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 18 Jul 2026 16:50:28 +0200 Subject: [PATCH 77/94] REVIEWED: `ImageToImage()`, reorganize conditionals checks optimization, align brackets --- src/rtextures.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/rtextures.c b/src/rtextures.c index afc69f166..15f009354 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -1233,15 +1233,13 @@ Image ImageFromImage(Image image, Rectangle rec) // Security check to avoid program crash if ((image.data == NULL) || (image.width == 0) || (image.height == 0)) return result; - // Basic rectangle validation: size smaller than image size - if ((rec.x >= 0) && (rec.y >= 0) && (rec.width > 0) && (rec.height > 0) && - (((int)rec.x + (int)rec.width) <= image.width) && - (((int)rec.y + (int)rec.height) <= image.height)) - { - - if (image.format >= PIXELFORMAT_COMPRESSED_DXT1_RGB) TRACELOG(LOG_WARNING, "IMAGE: Image manipulation not supported for compressed formats"); - else + if (image.format < PIXELFORMAT_COMPRESSED_DXT1_RGB) { + // Basic rectangle validation: size smaller than image size + if ((rec.x >= 0) && (rec.y >= 0) && (rec.width > 0) && (rec.height > 0) && + (((int)rec.x + (int)rec.width) <= image.width) && + (((int)rec.y + (int)rec.height) <= image.height)) + { int bytesPerPixel = GetPixelDataSize(1, 1, image.format); result.width = (int)rec.width; @@ -1252,11 +1250,14 @@ Image ImageFromImage(Image image, Rectangle rec) for (int y = 0; y < (int)rec.height; y++) { - memcpy(((unsigned char *)result.data) + y*(int)rec.width*bytesPerPixel, ((unsigned char *)image.data) + ((y + (int)rec.y)*image.width + (int)rec.x)*bytesPerPixel, (int)rec.width*bytesPerPixel); + memcpy(((unsigned char *)result.data) + y*(int)rec.width*bytesPerPixel, + ((unsigned char *)image.data) + ((y + (int)rec.y)*image.width + (int)rec.x)*bytesPerPixel, + (int)rec.width*bytesPerPixel); } + } + else TRACELOG(LOG_WARNING, "IMAGE: ImageToImage(), rectangle provided not valid"); } - } - else TRACELOG(LOG_WARNING, "IMAGE: Rectangle provided for ImageToImage not valid"); + else TRACELOG(LOG_WARNING, "IMAGE: Image manipulation not supported for compressed formats"); return result; } From ce6ac7d8c728f50b931b72bde2faf054c2288471 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 18 Jul 2026 14:50:44 +0000 Subject: [PATCH 78/94] rlparser: update raylib_api.* by CI --- tools/rlparser/output/raylib_api.json | 23 +- tools/rlparser/output/raylib_api.lua | 20 +- tools/rlparser/output/raylib_api.sexpr | 18 +- tools/rlparser/output/raylib_api.txt | 953 +++++++++++++------------ tools/rlparser/output/raylib_api.xml | 17 +- 5 files changed, 532 insertions(+), 499 deletions(-) diff --git a/tools/rlparser/output/raylib_api.json b/tools/rlparser/output/raylib_api.json index 2e6916737..cc6f210e4 100644 --- a/tools/rlparser/output/raylib_api.json +++ b/tools/rlparser/output/raylib_api.json @@ -4603,7 +4603,7 @@ }, { "name": "GetDirectoryPath", - "description": "Get full path for a given fileName with path (uses static string)", + "description": "Get full path for a provided fileName with path (uses static string)", "returnType": "const char *", "params": [ { @@ -4614,7 +4614,7 @@ }, { "name": "GetPrevDirectoryPath", - "description": "Get previous directory path for a given path (uses static string)", + "description": "Get previous directory path for a provided path (uses static string)", "returnType": "const char *", "params": [ { @@ -4657,7 +4657,7 @@ }, { "name": "IsPathFile", - "description": "Check if given path points to a file", + "description": "Check if provided path points to a file", "returnType": "bool", "params": [ { @@ -4668,7 +4668,18 @@ }, { "name": "IsPathDirectory", - "description": "Check if given path points to a directory", + "description": "Check if provided path points to a directory", + "returnType": "bool", + "params": [ + { + "type": "const char *", + "name": "path" + } + ] + }, + { + "name": "IsPathAbsolute", + "description": "Check if provided path is an absolute path", "returnType": "bool", "params": [ { @@ -5379,7 +5390,7 @@ }, { "name": "GetTouchPointId", - "description": "Get touch point identifier for given index", + "description": "Get touch point identifier for provided index", "returnType": "int", "params": [ { @@ -8099,7 +8110,7 @@ }, { "name": "ImageClearBackground", - "description": "Clear image background with given color", + "description": "Clear image background with provided color", "returnType": "void", "params": [ { diff --git a/tools/rlparser/output/raylib_api.lua b/tools/rlparser/output/raylib_api.lua index 574cfbf2d..5cdd5ebfc 100644 --- a/tools/rlparser/output/raylib_api.lua +++ b/tools/rlparser/output/raylib_api.lua @@ -4135,7 +4135,7 @@ return { }, { name = "GetDirectoryPath", - description = "Get full path for a given fileName with path (uses static string)", + description = "Get full path for a provided fileName with path (uses static string)", returnType = "const char *", params = { {type = "const char *", name = "filePath"} @@ -4143,7 +4143,7 @@ return { }, { name = "GetPrevDirectoryPath", - description = "Get previous directory path for a given path (uses static string)", + description = "Get previous directory path for a provided path (uses static string)", returnType = "const char *", params = { {type = "const char *", name = "dirPath"} @@ -4177,7 +4177,7 @@ return { }, { name = "IsPathFile", - description = "Check if given path points to a file", + description = "Check if provided path points to a file", returnType = "bool", params = { {type = "const char *", name = "path"} @@ -4185,7 +4185,15 @@ return { }, { name = "IsPathDirectory", - description = "Check if given path points to a directory", + description = "Check if provided path points to a directory", + returnType = "bool", + params = { + {type = "const char *", name = "path"} + } + }, + { + name = "IsPathAbsolute", + description = "Check if provided path is an absolute path", returnType = "bool", params = { {type = "const char *", name = "path"} @@ -4671,7 +4679,7 @@ return { }, { name = "GetTouchPointId", - description = "Get touch point identifier for given index", + description = "Get touch point identifier for provided index", returnType = "int", params = { {type = "int", name = "index"} @@ -6071,7 +6079,7 @@ return { }, { name = "ImageClearBackground", - description = "Clear image background with given color", + description = "Clear image background with provided color", returnType = "void", params = { {type = "Image *", name = "dst"}, diff --git a/tools/rlparser/output/raylib_api.sexpr b/tools/rlparser/output/raylib_api.sexpr index e57c282a3..387b64c68 100644 --- a/tools/rlparser/output/raylib_api.sexpr +++ b/tools/rlparser/output/raylib_api.sexpr @@ -3001,13 +3001,13 @@ ((type "const char *") (name "filePath")))) ((name "GetDirectoryPath") - (description "Get full path for a given fileName with path (uses static string)") + (description "Get full path for a provided fileName with path (uses static string)") (return-type "const char *") (params ((type "const char *") (name "filePath")))) ((name "GetPrevDirectoryPath") - (description "Get previous directory path for a given path (uses static string)") + (description "Get previous directory path for a provided path (uses static string)") (return-type "const char *") (params ((type "const char *") (name "dirPath")))) @@ -3033,13 +3033,19 @@ ((type "const char *") (name "dirPath")))) ((name "IsPathFile") - (description "Check if given path points to a file") + (description "Check if provided path points to a file") (return-type "bool") (params ((type "const char *") (name "path")))) ((name "IsPathDirectory") - (description "Check if given path points to a directory") + (description "Check if provided path points to a directory") + (return-type "bool") + (params + ((type "const char *") (name "path")))) + + ((name "IsPathAbsolute") + (description "Check if provided path is an absolute path") (return-type "bool") (params ((type "const char *") (name "path")))) @@ -3414,7 +3420,7 @@ ((type "int") (name "index")))) ((name "GetTouchPointId") - (description "Get touch point identifier for given index") + (description "Get touch point identifier for provided index") (return-type "int") (params ((type "int") (name "index")))) @@ -4544,7 +4550,7 @@ ((type "int") (name "y")))) ((name "ImageClearBackground") - (description "Clear image background with given color") + (description "Clear image background with provided color") (return-type "void") (params ((type "Image *") (name "dst")) diff --git a/tools/rlparser/output/raylib_api.txt b/tools/rlparser/output/raylib_api.txt index d0d60463c..76f5c2bae 100644 --- a/tools/rlparser/output/raylib_api.txt +++ b/tools/rlparser/output/raylib_api.txt @@ -995,7 +995,7 @@ Callback 006: AudioCallback() (2 input parameters) Param[1]: bufferData (type: void *) Param[2]: frames (type: unsigned int) -Functions found: 612 +Functions found: 613 Function 001: InitWindow() (3 input parameters) Name: InitWindow @@ -1739,12 +1739,12 @@ Function 137: GetFileNameWithoutExt() (1 input parameters) Function 138: GetDirectoryPath() (1 input parameters) Name: GetDirectoryPath Return type: const char * - Description: Get full path for a given fileName with path (uses static string) + Description: Get full path for a provided fileName with path (uses static string) Param[1]: filePath (type: const char *) Function 139: GetPrevDirectoryPath() (1 input parameters) Name: GetPrevDirectoryPath Return type: const char * - Description: Get previous directory path for a given path (uses static string) + Description: Get previous directory path for a provided path (uses static string) Param[1]: dirPath (type: const char *) Function 140: GetWorkingDirectory() (0 input parameters) Name: GetWorkingDirectory @@ -1769,255 +1769,260 @@ Function 143: ChangeDirectory() (1 input parameters) Function 144: IsPathFile() (1 input parameters) Name: IsPathFile Return type: bool - Description: Check if given path points to a file + Description: Check if provided path points to a file Param[1]: path (type: const char *) Function 145: IsPathDirectory() (1 input parameters) Name: IsPathDirectory Return type: bool - Description: Check if given path points to a directory + Description: Check if provided path points to a directory Param[1]: path (type: const char *) -Function 146: IsFileNameValid() (1 input parameters) +Function 146: IsPathAbsolute() (1 input parameters) + Name: IsPathAbsolute + Return type: bool + Description: Check if provided path is an absolute path + Param[1]: path (type: const char *) +Function 147: IsFileNameValid() (1 input parameters) Name: IsFileNameValid Return type: bool Description: Check if fileName is valid for the platform/OS Param[1]: fileName (type: const char *) -Function 147: LoadDirectoryFiles() (1 input parameters) +Function 148: LoadDirectoryFiles() (1 input parameters) Name: LoadDirectoryFiles Return type: FilePathList Description: Load directory filepaths, files and directories, no subdirs scan Param[1]: dirPath (type: const char *) -Function 148: LoadDirectoryFilesEx() (3 input parameters) +Function 149: LoadDirectoryFilesEx() (3 input parameters) Name: LoadDirectoryFilesEx Return type: FilePathList Description: Load directory filepaths with extension filtering and subdir scan; some filters available: '*.*','FILES*','DIRS*' Param[1]: basePath (type: const char *) Param[2]: filter (type: const char *) Param[3]: scanSubdirs (type: bool) -Function 149: UnloadDirectoryFiles() (1 input parameters) +Function 150: UnloadDirectoryFiles() (1 input parameters) Name: UnloadDirectoryFiles Return type: void Description: Unload filepaths Param[1]: files (type: FilePathList) -Function 150: IsFileDropped() (0 input parameters) +Function 151: IsFileDropped() (0 input parameters) Name: IsFileDropped Return type: bool Description: Check if file has been dropped into window No input parameters -Function 151: LoadDroppedFiles() (0 input parameters) +Function 152: LoadDroppedFiles() (0 input parameters) Name: LoadDroppedFiles Return type: FilePathList Description: Load dropped filepaths No input parameters -Function 152: UnloadDroppedFiles() (1 input parameters) +Function 153: UnloadDroppedFiles() (1 input parameters) Name: UnloadDroppedFiles Return type: void Description: Unload dropped filepaths Param[1]: files (type: FilePathList) -Function 153: GetDirectoryFileCount() (1 input parameters) +Function 154: GetDirectoryFileCount() (1 input parameters) Name: GetDirectoryFileCount Return type: unsigned int Description: Get the file count in a directory Param[1]: dirPath (type: const char *) -Function 154: GetDirectoryFileCountEx() (3 input parameters) +Function 155: GetDirectoryFileCountEx() (3 input parameters) Name: GetDirectoryFileCountEx Return type: unsigned int Description: Get the file count in a directory with extension filtering and recursive directory scan. Use 'DIR' in the filter string to include directories in the result Param[1]: basePath (type: const char *) Param[2]: filter (type: const char *) Param[3]: scanSubdirs (type: bool) -Function 155: CompressData() (3 input parameters) +Function 156: CompressData() (3 input parameters) Name: CompressData Return type: unsigned char * Description: Compress data (DEFLATE algorithm), memory must be MemFree() Param[1]: data (type: const unsigned char *) Param[2]: dataSize (type: int) Param[3]: compDataSize (type: int *) -Function 156: DecompressData() (3 input parameters) +Function 157: DecompressData() (3 input parameters) Name: DecompressData Return type: unsigned char * Description: Decompress data (DEFLATE algorithm), memory must be MemFree() Param[1]: compData (type: const unsigned char *) Param[2]: compDataSize (type: int) Param[3]: dataSize (type: int *) -Function 157: EncodeDataBase64() (3 input parameters) +Function 158: EncodeDataBase64() (3 input parameters) Name: EncodeDataBase64 Return type: char * Description: Encode data to Base64 string (includes NULL terminator), memory must be MemFree() Param[1]: data (type: const unsigned char *) Param[2]: dataSize (type: int) Param[3]: outputSize (type: int *) -Function 158: DecodeDataBase64() (2 input parameters) +Function 159: DecodeDataBase64() (2 input parameters) Name: DecodeDataBase64 Return type: unsigned char * Description: Decode Base64 string (expected NULL terminated), memory must be MemFree() Param[1]: text (type: const char *) Param[2]: outputSize (type: int *) -Function 159: ComputeCRC32() (2 input parameters) +Function 160: ComputeCRC32() (2 input parameters) Name: ComputeCRC32 Return type: unsigned int Description: Compute CRC32 hash code Param[1]: data (type: const unsigned char *) Param[2]: dataSize (type: int) -Function 160: ComputeMD5() (2 input parameters) +Function 161: ComputeMD5() (2 input parameters) Name: ComputeMD5 Return type: unsigned int * Description: Compute MD5 hash code, returns static int[4] (16 bytes) Param[1]: data (type: const unsigned char *) Param[2]: dataSize (type: int) -Function 161: ComputeSHA1() (2 input parameters) +Function 162: ComputeSHA1() (2 input parameters) Name: ComputeSHA1 Return type: unsigned int * Description: Compute SHA1 hash code, returns static int[5] (20 bytes) Param[1]: data (type: const unsigned char *) Param[2]: dataSize (type: int) -Function 162: ComputeSHA256() (2 input parameters) +Function 163: ComputeSHA256() (2 input parameters) Name: ComputeSHA256 Return type: unsigned int * Description: Compute SHA256 hash code, returns static int[8] (32 bytes) Param[1]: data (type: const unsigned char *) Param[2]: dataSize (type: int) -Function 163: LoadAutomationEventList() (1 input parameters) +Function 164: LoadAutomationEventList() (1 input parameters) Name: LoadAutomationEventList Return type: AutomationEventList Description: Load automation events list from file, NULL for empty list, capacity = MAX_AUTOMATION_EVENTS Param[1]: fileName (type: const char *) -Function 164: UnloadAutomationEventList() (1 input parameters) +Function 165: UnloadAutomationEventList() (1 input parameters) Name: UnloadAutomationEventList Return type: void Description: Unload automation events list from file Param[1]: list (type: AutomationEventList) -Function 165: ExportAutomationEventList() (2 input parameters) +Function 166: ExportAutomationEventList() (2 input parameters) Name: ExportAutomationEventList Return type: bool Description: Export automation events list as text file Param[1]: list (type: AutomationEventList) Param[2]: fileName (type: const char *) -Function 166: SetAutomationEventList() (1 input parameters) +Function 167: SetAutomationEventList() (1 input parameters) Name: SetAutomationEventList Return type: void Description: Set automation event list to record to Param[1]: list (type: AutomationEventList *) -Function 167: SetAutomationEventBaseFrame() (1 input parameters) +Function 168: SetAutomationEventBaseFrame() (1 input parameters) Name: SetAutomationEventBaseFrame Return type: void Description: Set automation event internal base frame to start recording Param[1]: frame (type: int) -Function 168: StartAutomationEventRecording() (0 input parameters) +Function 169: StartAutomationEventRecording() (0 input parameters) Name: StartAutomationEventRecording Return type: void Description: Start recording automation events (AutomationEventList must be set) No input parameters -Function 169: StopAutomationEventRecording() (0 input parameters) +Function 170: StopAutomationEventRecording() (0 input parameters) Name: StopAutomationEventRecording Return type: void Description: Stop recording automation events No input parameters -Function 170: PlayAutomationEvent() (1 input parameters) +Function 171: PlayAutomationEvent() (1 input parameters) Name: PlayAutomationEvent Return type: void Description: Play a recorded automation event Param[1]: event (type: AutomationEvent) -Function 171: IsKeyPressed() (1 input parameters) +Function 172: IsKeyPressed() (1 input parameters) Name: IsKeyPressed Return type: bool Description: Check if key has been pressed once Param[1]: key (type: int) -Function 172: IsKeyPressedRepeat() (1 input parameters) +Function 173: IsKeyPressedRepeat() (1 input parameters) Name: IsKeyPressedRepeat Return type: bool Description: Check if key has been pressed again Param[1]: key (type: int) -Function 173: IsKeyDown() (1 input parameters) +Function 174: IsKeyDown() (1 input parameters) Name: IsKeyDown Return type: bool Description: Check if key is being pressed Param[1]: key (type: int) -Function 174: IsKeyReleased() (1 input parameters) +Function 175: IsKeyReleased() (1 input parameters) Name: IsKeyReleased Return type: bool Description: Check if key has been released once Param[1]: key (type: int) -Function 175: IsKeyUp() (1 input parameters) +Function 176: IsKeyUp() (1 input parameters) Name: IsKeyUp Return type: bool Description: Check if key is NOT being pressed Param[1]: key (type: int) -Function 176: GetKeyPressed() (0 input parameters) +Function 177: GetKeyPressed() (0 input parameters) Name: GetKeyPressed Return type: int Description: Get key pressed (keycode), call it multiple times for keys queued, returns 0 when the queue is empty No input parameters -Function 177: GetCharPressed() (0 input parameters) +Function 178: GetCharPressed() (0 input parameters) Name: GetCharPressed Return type: int Description: Get char pressed (unicode), call it multiple times for chars queued, returns 0 when the queue is empty No input parameters -Function 178: GetKeyName() (1 input parameters) +Function 179: GetKeyName() (1 input parameters) Name: GetKeyName Return type: const char * Description: Get name of a QWERTY key on the current keyboard layout (eg returns string 'q' for KEY_A on an AZERTY keyboard) Param[1]: key (type: int) -Function 179: SetExitKey() (1 input parameters) +Function 180: SetExitKey() (1 input parameters) Name: SetExitKey Return type: void Description: Set a custom key to exit program (default is ESC) Param[1]: key (type: int) -Function 180: IsGamepadAvailable() (1 input parameters) +Function 181: IsGamepadAvailable() (1 input parameters) Name: IsGamepadAvailable Return type: bool Description: Check if gamepad is available Param[1]: gamepad (type: int) -Function 181: GetGamepadName() (1 input parameters) +Function 182: GetGamepadName() (1 input parameters) Name: GetGamepadName Return type: const char * Description: Get gamepad internal name id Param[1]: gamepad (type: int) -Function 182: IsGamepadButtonPressed() (2 input parameters) +Function 183: IsGamepadButtonPressed() (2 input parameters) Name: IsGamepadButtonPressed Return type: bool Description: Check if gamepad button has been pressed once Param[1]: gamepad (type: int) Param[2]: button (type: int) -Function 183: IsGamepadButtonDown() (2 input parameters) +Function 184: IsGamepadButtonDown() (2 input parameters) Name: IsGamepadButtonDown Return type: bool Description: Check if gamepad button is being pressed Param[1]: gamepad (type: int) Param[2]: button (type: int) -Function 184: IsGamepadButtonReleased() (2 input parameters) +Function 185: IsGamepadButtonReleased() (2 input parameters) Name: IsGamepadButtonReleased Return type: bool Description: Check if gamepad button has been released once Param[1]: gamepad (type: int) Param[2]: button (type: int) -Function 185: IsGamepadButtonUp() (2 input parameters) +Function 186: IsGamepadButtonUp() (2 input parameters) Name: IsGamepadButtonUp Return type: bool Description: Check if gamepad button is NOT being pressed Param[1]: gamepad (type: int) Param[2]: button (type: int) -Function 186: GetGamepadButtonPressed() (0 input parameters) +Function 187: GetGamepadButtonPressed() (0 input parameters) Name: GetGamepadButtonPressed Return type: int Description: Get the last gamepad button pressed No input parameters -Function 187: GetGamepadAxisCount() (1 input parameters) +Function 188: GetGamepadAxisCount() (1 input parameters) Name: GetGamepadAxisCount Return type: int Description: Get axis count for a gamepad Param[1]: gamepad (type: int) -Function 188: GetGamepadAxisMovement() (2 input parameters) +Function 189: GetGamepadAxisMovement() (2 input parameters) Name: GetGamepadAxisMovement Return type: float Description: Get movement value for a gamepad axis Param[1]: gamepad (type: int) Param[2]: axis (type: int) -Function 189: SetGamepadMappings() (1 input parameters) +Function 190: SetGamepadMappings() (1 input parameters) Name: SetGamepadMappings Return type: int Description: Set internal gamepad mappings (SDL_GameControllerDB) Param[1]: mappings (type: const char *) -Function 190: SetGamepadVibration() (4 input parameters) +Function 191: SetGamepadVibration() (4 input parameters) Name: SetGamepadVibration Return type: void Description: Set gamepad vibration for both motors (duration in seconds) @@ -2025,151 +2030,151 @@ Function 190: SetGamepadVibration() (4 input parameters) Param[2]: leftMotor (type: float) Param[3]: rightMotor (type: float) Param[4]: duration (type: float) -Function 191: IsMouseButtonPressed() (1 input parameters) +Function 192: IsMouseButtonPressed() (1 input parameters) Name: IsMouseButtonPressed Return type: bool Description: Check if mouse button has been pressed once Param[1]: button (type: int) -Function 192: IsMouseButtonDown() (1 input parameters) +Function 193: IsMouseButtonDown() (1 input parameters) Name: IsMouseButtonDown Return type: bool Description: Check if mouse button is being pressed Param[1]: button (type: int) -Function 193: IsMouseButtonReleased() (1 input parameters) +Function 194: IsMouseButtonReleased() (1 input parameters) Name: IsMouseButtonReleased Return type: bool Description: Check if mouse button has been released once Param[1]: button (type: int) -Function 194: IsMouseButtonUp() (1 input parameters) +Function 195: IsMouseButtonUp() (1 input parameters) Name: IsMouseButtonUp Return type: bool Description: Check if mouse button is NOT being pressed Param[1]: button (type: int) -Function 195: GetMouseX() (0 input parameters) +Function 196: GetMouseX() (0 input parameters) Name: GetMouseX Return type: int Description: Get mouse position X No input parameters -Function 196: GetMouseY() (0 input parameters) +Function 197: GetMouseY() (0 input parameters) Name: GetMouseY Return type: int Description: Get mouse position Y No input parameters -Function 197: GetMousePosition() (0 input parameters) +Function 198: GetMousePosition() (0 input parameters) Name: GetMousePosition Return type: Vector2 Description: Get mouse position XY No input parameters -Function 198: GetMouseDelta() (0 input parameters) +Function 199: GetMouseDelta() (0 input parameters) Name: GetMouseDelta Return type: Vector2 Description: Get mouse delta between frames No input parameters -Function 199: SetMousePosition() (2 input parameters) +Function 200: SetMousePosition() (2 input parameters) Name: SetMousePosition Return type: void Description: Set mouse position XY Param[1]: x (type: int) Param[2]: y (type: int) -Function 200: SetMouseOffset() (2 input parameters) +Function 201: SetMouseOffset() (2 input parameters) Name: SetMouseOffset Return type: void Description: Set mouse offset Param[1]: offsetX (type: int) Param[2]: offsetY (type: int) -Function 201: SetMouseScale() (2 input parameters) +Function 202: SetMouseScale() (2 input parameters) Name: SetMouseScale Return type: void Description: Set mouse scaling Param[1]: scaleX (type: float) Param[2]: scaleY (type: float) -Function 202: GetMouseWheelMove() (0 input parameters) +Function 203: GetMouseWheelMove() (0 input parameters) Name: GetMouseWheelMove Return type: float Description: Get mouse wheel movement for X or Y, whichever is larger No input parameters -Function 203: GetMouseWheelMoveV() (0 input parameters) +Function 204: GetMouseWheelMoveV() (0 input parameters) Name: GetMouseWheelMoveV Return type: Vector2 Description: Get mouse wheel movement for both X and Y No input parameters -Function 204: SetMouseCursor() (1 input parameters) +Function 205: SetMouseCursor() (1 input parameters) Name: SetMouseCursor Return type: void Description: Set mouse cursor Param[1]: cursor (type: int) -Function 205: GetTouchX() (0 input parameters) +Function 206: GetTouchX() (0 input parameters) Name: GetTouchX Return type: int Description: Get touch position X for touch point 0 (relative to screen size) No input parameters -Function 206: GetTouchY() (0 input parameters) +Function 207: GetTouchY() (0 input parameters) Name: GetTouchY Return type: int Description: Get touch position Y for touch point 0 (relative to screen size) No input parameters -Function 207: GetTouchPosition() (1 input parameters) +Function 208: GetTouchPosition() (1 input parameters) Name: GetTouchPosition Return type: Vector2 Description: Get touch position XY for a touch point index (relative to screen size) Param[1]: index (type: int) -Function 208: GetTouchPointId() (1 input parameters) +Function 209: GetTouchPointId() (1 input parameters) Name: GetTouchPointId Return type: int - Description: Get touch point identifier for given index + Description: Get touch point identifier for provided index Param[1]: index (type: int) -Function 209: GetTouchPointCount() (0 input parameters) +Function 210: GetTouchPointCount() (0 input parameters) Name: GetTouchPointCount Return type: int Description: Get number of touch points No input parameters -Function 210: SetGesturesEnabled() (1 input parameters) +Function 211: SetGesturesEnabled() (1 input parameters) Name: SetGesturesEnabled Return type: void Description: Enable a set of gestures using flags Param[1]: flags (type: unsigned int) -Function 211: IsGestureDetected() (1 input parameters) +Function 212: IsGestureDetected() (1 input parameters) Name: IsGestureDetected Return type: bool Description: Check if gesture has been detected Param[1]: gesture (type: unsigned int) -Function 212: GetGestureDetected() (0 input parameters) +Function 213: GetGestureDetected() (0 input parameters) Name: GetGestureDetected Return type: int Description: Get latest detected gesture No input parameters -Function 213: GetGestureHoldDuration() (0 input parameters) +Function 214: GetGestureHoldDuration() (0 input parameters) Name: GetGestureHoldDuration Return type: float Description: Get gesture hold time in seconds No input parameters -Function 214: GetGestureDragVector() (0 input parameters) +Function 215: GetGestureDragVector() (0 input parameters) Name: GetGestureDragVector Return type: Vector2 Description: Get gesture drag vector No input parameters -Function 215: GetGestureDragAngle() (0 input parameters) +Function 216: GetGestureDragAngle() (0 input parameters) Name: GetGestureDragAngle Return type: float Description: Get gesture drag angle No input parameters -Function 216: GetGesturePinchVector() (0 input parameters) +Function 217: GetGesturePinchVector() (0 input parameters) Name: GetGesturePinchVector Return type: Vector2 Description: Get gesture pinch delta No input parameters -Function 217: GetGesturePinchAngle() (0 input parameters) +Function 218: GetGesturePinchAngle() (0 input parameters) Name: GetGesturePinchAngle Return type: float Description: Get gesture pinch angle No input parameters -Function 218: UpdateCamera() (2 input parameters) +Function 219: UpdateCamera() (2 input parameters) Name: UpdateCamera Return type: void Description: Update camera position for selected mode Param[1]: camera (type: Camera *) Param[2]: mode (type: int) -Function 219: UpdateCameraPro() (4 input parameters) +Function 220: UpdateCameraPro() (4 input parameters) Name: UpdateCameraPro Return type: void Description: Update camera movement/rotation @@ -2177,36 +2182,36 @@ Function 219: UpdateCameraPro() (4 input parameters) Param[2]: movement (type: Vector3) Param[3]: rotation (type: Vector3) Param[4]: zoom (type: float) -Function 220: SetShapesTexture() (2 input parameters) +Function 221: SetShapesTexture() (2 input parameters) Name: SetShapesTexture Return type: void Description: Set texture and rectangle to be used on shapes drawing Param[1]: texture (type: Texture2D) Param[2]: rec (type: Rectangle) -Function 221: GetShapesTexture() (0 input parameters) +Function 222: GetShapesTexture() (0 input parameters) Name: GetShapesTexture Return type: Texture2D Description: Get texture that is used for shapes drawing No input parameters -Function 222: GetShapesTextureRectangle() (0 input parameters) +Function 223: GetShapesTextureRectangle() (0 input parameters) Name: GetShapesTextureRectangle Return type: Rectangle Description: Get texture source rectangle that is used for shapes drawing No input parameters -Function 223: DrawPixel() (3 input parameters) +Function 224: DrawPixel() (3 input parameters) Name: DrawPixel Return type: void Description: Draw a pixel using geometry [Can be slow, use with care] Param[1]: posX (type: int) Param[2]: posY (type: int) Param[3]: color (type: Color) -Function 224: DrawPixelV() (2 input parameters) +Function 225: DrawPixelV() (2 input parameters) Name: DrawPixelV Return type: void Description: Draw a pixel using geometry (Vector version) [Can be slow, use with care] Param[1]: position (type: Vector2) Param[2]: color (type: Color) -Function 225: DrawLine() (5 input parameters) +Function 226: DrawLine() (5 input parameters) Name: DrawLine Return type: void Description: Draw a line @@ -2215,14 +2220,14 @@ Function 225: DrawLine() (5 input parameters) Param[3]: endPosX (type: int) Param[4]: endPosY (type: int) Param[5]: color (type: Color) -Function 226: DrawLineV() (3 input parameters) +Function 227: DrawLineV() (3 input parameters) Name: DrawLineV Return type: void Description: Draw a line (using gl lines) Param[1]: startPos (type: Vector2) Param[2]: endPos (type: Vector2) Param[3]: color (type: Color) -Function 227: DrawLineEx() (4 input parameters) +Function 228: DrawLineEx() (4 input parameters) Name: DrawLineEx Return type: void Description: Draw a line (using triangles/quads) @@ -2230,14 +2235,14 @@ Function 227: DrawLineEx() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 228: DrawLineStrip() (3 input parameters) +Function 229: DrawLineStrip() (3 input parameters) Name: DrawLineStrip Return type: void Description: Draw lines sequence (using gl lines) Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 229: DrawLineBezier() (4 input parameters) +Function 230: DrawLineBezier() (4 input parameters) Name: DrawLineBezier Return type: void Description: Draw line segment cubic-bezier in-out interpolation @@ -2245,7 +2250,7 @@ Function 229: DrawLineBezier() (4 input parameters) Param[2]: endPos (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 230: DrawLineDashed() (5 input parameters) +Function 231: DrawLineDashed() (5 input parameters) Name: DrawLineDashed Return type: void Description: Draw a dashed line @@ -2254,7 +2259,7 @@ Function 230: DrawLineDashed() (5 input parameters) Param[3]: dashSize (type: int) Param[4]: spaceSize (type: int) Param[5]: color (type: Color) -Function 231: DrawTriangle() (4 input parameters) +Function 232: DrawTriangle() (4 input parameters) Name: DrawTriangle Return type: void Description: Draw a color-filled triangle, counter-clockwise vertex order @@ -2262,7 +2267,7 @@ Function 231: DrawTriangle() (4 input parameters) Param[2]: v2 (type: Vector2) Param[3]: v3 (type: Vector2) Param[4]: color (type: Color) -Function 232: DrawTriangleGradient() (6 input parameters) +Function 233: DrawTriangleGradient() (6 input parameters) Name: DrawTriangleGradient Return type: void Description: Draw triangle with interpolated colors, counter-clockwise vertex/color order @@ -2272,7 +2277,7 @@ Function 232: DrawTriangleGradient() (6 input parameters) Param[4]: c1 (type: Color) Param[5]: c2 (type: Color) Param[6]: c3 (type: Color) -Function 233: DrawTriangleLines() (4 input parameters) +Function 234: DrawTriangleLines() (4 input parameters) Name: DrawTriangleLines Return type: void Description: Draw triangle outline, counter-clockwise vertex order @@ -2280,21 +2285,21 @@ Function 233: DrawTriangleLines() (4 input parameters) Param[2]: v2 (type: Vector2) Param[3]: v3 (type: Vector2) Param[4]: color (type: Color) -Function 234: DrawTriangleFan() (3 input parameters) +Function 235: DrawTriangleFan() (3 input parameters) Name: DrawTriangleFan Return type: void Description: Draw a triangle fan defined by points (first vertex is the center) Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 235: DrawTriangleStrip() (3 input parameters) +Function 236: DrawTriangleStrip() (3 input parameters) Name: DrawTriangleStrip Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: const Vector2 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 236: DrawRectangle() (5 input parameters) +Function 237: DrawRectangle() (5 input parameters) Name: DrawRectangle Return type: void Description: Draw a color-filled rectangle @@ -2303,20 +2308,20 @@ Function 236: DrawRectangle() (5 input parameters) Param[3]: width (type: int) Param[4]: height (type: int) Param[5]: color (type: Color) -Function 237: DrawRectangleV() (3 input parameters) +Function 238: DrawRectangleV() (3 input parameters) Name: DrawRectangleV Return type: void Description: Draw a color-filled rectangle (Vector version) Param[1]: position (type: Vector2) Param[2]: size (type: Vector2) Param[3]: color (type: Color) -Function 238: DrawRectangleRec() (2 input parameters) +Function 239: DrawRectangleRec() (2 input parameters) Name: DrawRectangleRec Return type: void Description: Draw a color-filled rectangle Param[1]: rec (type: Rectangle) Param[2]: color (type: Color) -Function 239: DrawRectanglePro() (4 input parameters) +Function 240: DrawRectanglePro() (4 input parameters) Name: DrawRectanglePro Return type: void Description: Draw a color-filled rectangle with pro parameters @@ -2324,7 +2329,7 @@ Function 239: DrawRectanglePro() (4 input parameters) Param[2]: origin (type: Vector2) Param[3]: rotation (type: float) Param[4]: color (type: Color) -Function 240: DrawRectangleGradientV() (6 input parameters) +Function 241: DrawRectangleGradientV() (6 input parameters) Name: DrawRectangleGradientV Return type: void Description: Draw a vertical-gradient-filled rectangle @@ -2334,7 +2339,7 @@ Function 240: DrawRectangleGradientV() (6 input parameters) Param[4]: height (type: int) Param[5]: top (type: Color) Param[6]: bottom (type: Color) -Function 241: DrawRectangleGradientH() (6 input parameters) +Function 242: DrawRectangleGradientH() (6 input parameters) Name: DrawRectangleGradientH Return type: void Description: Draw a horizontal-gradient-filled rectangle @@ -2344,7 +2349,7 @@ Function 241: DrawRectangleGradientH() (6 input parameters) Param[4]: height (type: int) Param[5]: left (type: Color) Param[6]: right (type: Color) -Function 242: DrawRectangleGradientEx() (5 input parameters) +Function 243: DrawRectangleGradientEx() (5 input parameters) Name: DrawRectangleGradientEx Return type: void Description: Draw a gradient-filled rectangle with custom vertex colors, counter-clockwise color order @@ -2353,7 +2358,7 @@ Function 242: DrawRectangleGradientEx() (5 input parameters) Param[3]: col2 (type: Color) Param[4]: col3 (type: Color) Param[5]: col4 (type: Color) -Function 243: DrawRectangleLines() (5 input parameters) +Function 244: DrawRectangleLines() (5 input parameters) Name: DrawRectangleLines Return type: void Description: Draw rectangle outline @@ -2362,14 +2367,14 @@ Function 243: DrawRectangleLines() (5 input parameters) Param[3]: width (type: int) Param[4]: height (type: int) Param[5]: color (type: Color) -Function 244: DrawRectangleLinesEx() (3 input parameters) +Function 245: DrawRectangleLinesEx() (3 input parameters) Name: DrawRectangleLinesEx Return type: void Description: Draw rectangle outline with line thickness Param[1]: rec (type: Rectangle) Param[2]: thick (type: float) Param[3]: color (type: Color) -Function 245: DrawRectangleRounded() (4 input parameters) +Function 246: DrawRectangleRounded() (4 input parameters) Name: DrawRectangleRounded Return type: void Description: Draw rectangle with rounded edges @@ -2377,7 +2382,7 @@ Function 245: DrawRectangleRounded() (4 input parameters) Param[2]: roundness (type: float) Param[3]: segments (type: int) Param[4]: color (type: Color) -Function 246: DrawRectangleRoundedLines() (4 input parameters) +Function 247: DrawRectangleRoundedLines() (4 input parameters) Name: DrawRectangleRoundedLines Return type: void Description: Draw rectangle lines with rounded edges @@ -2385,7 +2390,7 @@ Function 246: DrawRectangleRoundedLines() (4 input parameters) Param[2]: roundness (type: float) Param[3]: segments (type: int) Param[4]: color (type: Color) -Function 247: DrawRectangleRoundedLinesEx() (5 input parameters) +Function 248: DrawRectangleRoundedLinesEx() (5 input parameters) Name: DrawRectangleRoundedLinesEx Return type: void Description: Draw rectangle lines with rounded edges outline and line thickness @@ -2394,7 +2399,7 @@ Function 247: DrawRectangleRoundedLinesEx() (5 input parameters) Param[3]: segments (type: int) Param[4]: thick (type: float) Param[5]: color (type: Color) -Function 248: DrawPoly() (5 input parameters) +Function 249: DrawPoly() (5 input parameters) Name: DrawPoly Return type: void Description: Draw a polygon of n sides @@ -2403,7 +2408,7 @@ Function 248: DrawPoly() (5 input parameters) Param[3]: radius (type: float) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 249: DrawPolyLines() (5 input parameters) +Function 250: DrawPolyLines() (5 input parameters) Name: DrawPolyLines Return type: void Description: Draw a polygon outline of n sides @@ -2412,7 +2417,7 @@ Function 249: DrawPolyLines() (5 input parameters) Param[3]: radius (type: float) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 250: DrawPolyLinesEx() (6 input parameters) +Function 251: DrawPolyLinesEx() (6 input parameters) Name: DrawPolyLinesEx Return type: void Description: Draw a polygon outline of n sides with line thickness @@ -2422,7 +2427,7 @@ Function 250: DrawPolyLinesEx() (6 input parameters) Param[4]: rotation (type: float) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 251: DrawCircle() (4 input parameters) +Function 252: DrawCircle() (4 input parameters) Name: DrawCircle Return type: void Description: Draw a color-filled circle @@ -2430,14 +2435,14 @@ Function 251: DrawCircle() (4 input parameters) Param[2]: centerY (type: int) Param[3]: radius (type: float) Param[4]: color (type: Color) -Function 252: DrawCircleV() (3 input parameters) +Function 253: DrawCircleV() (3 input parameters) Name: DrawCircleV Return type: void Description: Draw a color-filled circle (Vector version) Param[1]: center (type: Vector2) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 253: DrawCircleGradient() (4 input parameters) +Function 254: DrawCircleGradient() (4 input parameters) Name: DrawCircleGradient Return type: void Description: Draw a gradient-filled circle @@ -2445,7 +2450,7 @@ Function 253: DrawCircleGradient() (4 input parameters) Param[2]: radius (type: float) Param[3]: inner (type: Color) Param[4]: outer (type: Color) -Function 254: DrawCircleSector() (6 input parameters) +Function 255: DrawCircleSector() (6 input parameters) Name: DrawCircleSector Return type: void Description: Draw a piece of a circle @@ -2455,7 +2460,7 @@ Function 254: DrawCircleSector() (6 input parameters) Param[4]: endAngle (type: float) Param[5]: segments (type: int) Param[6]: color (type: Color) -Function 255: DrawCircleSectorLines() (6 input parameters) +Function 256: DrawCircleSectorLines() (6 input parameters) Name: DrawCircleSectorLines Return type: void Description: Draw circle sector outline @@ -2465,7 +2470,7 @@ Function 255: DrawCircleSectorLines() (6 input parameters) Param[4]: endAngle (type: float) Param[5]: segments (type: int) Param[6]: color (type: Color) -Function 256: DrawCircleLines() (4 input parameters) +Function 257: DrawCircleLines() (4 input parameters) Name: DrawCircleLines Return type: void Description: Draw circle outline @@ -2473,14 +2478,14 @@ Function 256: DrawCircleLines() (4 input parameters) Param[2]: centerY (type: int) Param[3]: radius (type: float) Param[4]: color (type: Color) -Function 257: DrawCircleLinesV() (3 input parameters) +Function 258: DrawCircleLinesV() (3 input parameters) Name: DrawCircleLinesV Return type: void Description: Draw circle outline (Vector version) Param[1]: center (type: Vector2) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 258: DrawCircleLinesEx() (4 input parameters) +Function 259: DrawCircleLinesEx() (4 input parameters) Name: DrawCircleLinesEx Return type: void Description: Draw circle outline with line thickness @@ -2488,7 +2493,7 @@ Function 258: DrawCircleLinesEx() (4 input parameters) Param[2]: radius (type: float) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 259: DrawEllipse() (5 input parameters) +Function 260: DrawEllipse() (5 input parameters) Name: DrawEllipse Return type: void Description: Draw ellipse @@ -2497,7 +2502,7 @@ Function 259: DrawEllipse() (5 input parameters) Param[3]: radiusH (type: float) Param[4]: radiusV (type: float) Param[5]: color (type: Color) -Function 260: DrawEllipseV() (4 input parameters) +Function 261: DrawEllipseV() (4 input parameters) Name: DrawEllipseV Return type: void Description: Draw ellipse (Vector version) @@ -2505,7 +2510,7 @@ Function 260: DrawEllipseV() (4 input parameters) Param[2]: radiusH (type: float) Param[3]: radiusV (type: float) Param[4]: color (type: Color) -Function 261: DrawEllipseLines() (5 input parameters) +Function 262: DrawEllipseLines() (5 input parameters) Name: DrawEllipseLines Return type: void Description: Draw ellipse outline @@ -2514,7 +2519,7 @@ Function 261: DrawEllipseLines() (5 input parameters) Param[3]: radiusH (type: float) Param[4]: radiusV (type: float) Param[5]: color (type: Color) -Function 262: DrawEllipseLinesV() (4 input parameters) +Function 263: DrawEllipseLinesV() (4 input parameters) Name: DrawEllipseLinesV Return type: void Description: Draw ellipse outline (Vector version) @@ -2522,7 +2527,7 @@ Function 262: DrawEllipseLinesV() (4 input parameters) Param[2]: radiusH (type: float) Param[3]: radiusV (type: float) Param[4]: color (type: Color) -Function 263: DrawRing() (7 input parameters) +Function 264: DrawRing() (7 input parameters) Name: DrawRing Return type: void Description: Draw ring @@ -2533,7 +2538,7 @@ Function 263: DrawRing() (7 input parameters) Param[5]: endAngle (type: float) Param[6]: segments (type: int) Param[7]: color (type: Color) -Function 264: DrawRingLines() (7 input parameters) +Function 265: DrawRingLines() (7 input parameters) Name: DrawRingLines Return type: void Description: Draw ring outline @@ -2544,7 +2549,7 @@ Function 264: DrawRingLines() (7 input parameters) Param[5]: endAngle (type: float) Param[6]: segments (type: int) Param[7]: color (type: Color) -Function 265: DrawSplineLinear() (4 input parameters) +Function 266: DrawSplineLinear() (4 input parameters) Name: DrawSplineLinear Return type: void Description: Draw spline: Linear, minimum 2 points @@ -2552,7 +2557,7 @@ Function 265: DrawSplineLinear() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 266: DrawSplineBasis() (4 input parameters) +Function 267: DrawSplineBasis() (4 input parameters) Name: DrawSplineBasis Return type: void Description: Draw spline: B-Spline, minimum 4 points @@ -2560,7 +2565,7 @@ Function 266: DrawSplineBasis() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 267: DrawSplineCatmullRom() (4 input parameters) +Function 268: DrawSplineCatmullRom() (4 input parameters) Name: DrawSplineCatmullRom Return type: void Description: Draw spline: Catmull-Rom, minimum 4 points @@ -2568,7 +2573,7 @@ Function 267: DrawSplineCatmullRom() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 268: DrawSplineBezierQuadratic() (4 input parameters) +Function 269: DrawSplineBezierQuadratic() (4 input parameters) Name: DrawSplineBezierQuadratic Return type: void Description: Draw spline: Quadratic Bezier, minimum 3 points (1 control point): [p1, c2, p3, c4...] @@ -2576,7 +2581,7 @@ Function 268: DrawSplineBezierQuadratic() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 269: DrawSplineBezierCubic() (4 input parameters) +Function 270: DrawSplineBezierCubic() (4 input parameters) Name: DrawSplineBezierCubic Return type: void Description: Draw spline: Cubic Bezier, minimum 4 points (2 control points): [p1, c2, c3, p4, c5, c6...] @@ -2584,7 +2589,7 @@ Function 269: DrawSplineBezierCubic() (4 input parameters) Param[2]: pointCount (type: int) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 270: DrawSplineSegmentLinear() (4 input parameters) +Function 271: DrawSplineSegmentLinear() (4 input parameters) Name: DrawSplineSegmentLinear Return type: void Description: Draw spline segment: Linear, 2 points @@ -2592,7 +2597,7 @@ Function 270: DrawSplineSegmentLinear() (4 input parameters) Param[2]: p2 (type: Vector2) Param[3]: thick (type: float) Param[4]: color (type: Color) -Function 271: DrawSplineSegmentBasis() (6 input parameters) +Function 272: DrawSplineSegmentBasis() (6 input parameters) Name: DrawSplineSegmentBasis Return type: void Description: Draw spline segment: B-Spline, 4 points @@ -2602,7 +2607,7 @@ Function 271: DrawSplineSegmentBasis() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 272: DrawSplineSegmentCatmullRom() (6 input parameters) +Function 273: DrawSplineSegmentCatmullRom() (6 input parameters) Name: DrawSplineSegmentCatmullRom Return type: void Description: Draw spline segment: Catmull-Rom, 4 points @@ -2612,7 +2617,7 @@ Function 272: DrawSplineSegmentCatmullRom() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 273: DrawSplineSegmentBezierQuadratic() (5 input parameters) +Function 274: DrawSplineSegmentBezierQuadratic() (5 input parameters) Name: DrawSplineSegmentBezierQuadratic Return type: void Description: Draw spline segment: Quadratic Bezier, 2 points, 1 control point @@ -2621,7 +2626,7 @@ Function 273: DrawSplineSegmentBezierQuadratic() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: thick (type: float) Param[5]: color (type: Color) -Function 274: DrawSplineSegmentBezierCubic() (6 input parameters) +Function 275: DrawSplineSegmentBezierCubic() (6 input parameters) Name: DrawSplineSegmentBezierCubic Return type: void Description: Draw spline segment: Cubic Bezier, 2 points, 2 control points @@ -2631,14 +2636,14 @@ Function 274: DrawSplineSegmentBezierCubic() (6 input parameters) Param[4]: p4 (type: Vector2) Param[5]: thick (type: float) Param[6]: color (type: Color) -Function 275: GetSplinePointLinear() (3 input parameters) +Function 276: GetSplinePointLinear() (3 input parameters) Name: GetSplinePointLinear Return type: Vector2 Description: Get (evaluate) spline point: Linear Param[1]: startPos (type: Vector2) Param[2]: endPos (type: Vector2) Param[3]: t (type: float) -Function 276: GetSplinePointBasis() (5 input parameters) +Function 277: GetSplinePointBasis() (5 input parameters) Name: GetSplinePointBasis Return type: Vector2 Description: Get (evaluate) spline point: B-Spline @@ -2647,7 +2652,7 @@ Function 276: GetSplinePointBasis() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 277: GetSplinePointCatmullRom() (5 input parameters) +Function 278: GetSplinePointCatmullRom() (5 input parameters) Name: GetSplinePointCatmullRom Return type: Vector2 Description: Get (evaluate) spline point: Catmull-Rom @@ -2656,7 +2661,7 @@ Function 277: GetSplinePointCatmullRom() (5 input parameters) Param[3]: p3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 278: GetSplinePointBezierQuadratic() (4 input parameters) +Function 279: GetSplinePointBezierQuadratic() (4 input parameters) Name: GetSplinePointBezierQuadratic Return type: Vector2 Description: Get (evaluate) spline point: Quadratic Bezier @@ -2664,7 +2669,7 @@ Function 278: GetSplinePointBezierQuadratic() (4 input parameters) Param[2]: c2 (type: Vector2) Param[3]: p3 (type: Vector2) Param[4]: t (type: float) -Function 279: GetSplinePointBezierCubic() (5 input parameters) +Function 280: GetSplinePointBezierCubic() (5 input parameters) Name: GetSplinePointBezierCubic Return type: Vector2 Description: Get (evaluate) spline point: Cubic Bezier @@ -2673,13 +2678,13 @@ Function 279: GetSplinePointBezierCubic() (5 input parameters) Param[3]: c3 (type: Vector2) Param[4]: p4 (type: Vector2) Param[5]: t (type: float) -Function 280: CheckCollisionRecs() (2 input parameters) +Function 281: CheckCollisionRecs() (2 input parameters) Name: CheckCollisionRecs Return type: bool Description: Check collision between two rectangles Param[1]: rec1 (type: Rectangle) Param[2]: rec2 (type: Rectangle) -Function 281: CheckCollisionCircles() (4 input parameters) +Function 282: CheckCollisionCircles() (4 input parameters) Name: CheckCollisionCircles Return type: bool Description: Check collision between two circles @@ -2687,14 +2692,14 @@ Function 281: CheckCollisionCircles() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector2) Param[4]: radius2 (type: float) -Function 282: CheckCollisionCircleRec() (3 input parameters) +Function 283: CheckCollisionCircleRec() (3 input parameters) Name: CheckCollisionCircleRec Return type: bool Description: Check collision between circle and rectangle Param[1]: center (type: Vector2) Param[2]: radius (type: float) Param[3]: rec (type: Rectangle) -Function 283: CheckCollisionCircleLine() (4 input parameters) +Function 284: CheckCollisionCircleLine() (4 input parameters) Name: CheckCollisionCircleLine Return type: bool Description: Check if circle collides with a line created between two points [p1] and [p2] @@ -2702,20 +2707,20 @@ Function 283: CheckCollisionCircleLine() (4 input parameters) Param[2]: radius (type: float) Param[3]: p1 (type: Vector2) Param[4]: p2 (type: Vector2) -Function 284: CheckCollisionPointRec() (2 input parameters) +Function 285: CheckCollisionPointRec() (2 input parameters) Name: CheckCollisionPointRec Return type: bool Description: Check if point is inside rectangle Param[1]: point (type: Vector2) Param[2]: rec (type: Rectangle) -Function 285: CheckCollisionPointCircle() (3 input parameters) +Function 286: CheckCollisionPointCircle() (3 input parameters) Name: CheckCollisionPointCircle Return type: bool Description: Check if point is inside circle Param[1]: point (type: Vector2) Param[2]: center (type: Vector2) Param[3]: radius (type: float) -Function 286: CheckCollisionPointTriangle() (4 input parameters) +Function 287: CheckCollisionPointTriangle() (4 input parameters) Name: CheckCollisionPointTriangle Return type: bool Description: Check if point is inside a triangle @@ -2723,7 +2728,7 @@ Function 286: CheckCollisionPointTriangle() (4 input parameters) Param[2]: p1 (type: Vector2) Param[3]: p2 (type: Vector2) Param[4]: p3 (type: Vector2) -Function 287: CheckCollisionPointLine() (4 input parameters) +Function 288: CheckCollisionPointLine() (4 input parameters) Name: CheckCollisionPointLine Return type: bool Description: Check if point belongs to line created between two points [p1] and [p2] with defined margin in pixels [threshold] @@ -2731,14 +2736,14 @@ Function 287: CheckCollisionPointLine() (4 input parameters) Param[2]: p1 (type: Vector2) Param[3]: p2 (type: Vector2) Param[4]: threshold (type: int) -Function 288: CheckCollisionPointPoly() (3 input parameters) +Function 289: CheckCollisionPointPoly() (3 input parameters) Name: CheckCollisionPointPoly Return type: bool Description: Check if point is within a polygon described by array of vertices Param[1]: point (type: Vector2) Param[2]: points (type: const Vector2 *) Param[3]: pointCount (type: int) -Function 289: CheckCollisionLines() (5 input parameters) +Function 290: CheckCollisionLines() (5 input parameters) Name: CheckCollisionLines Return type: bool Description: Check the collision between two lines defined by two points each, returns collision point by reference @@ -2747,18 +2752,18 @@ Function 289: CheckCollisionLines() (5 input parameters) Param[3]: startPos2 (type: Vector2) Param[4]: endPos2 (type: Vector2) Param[5]: collisionPoint (type: Vector2 *) -Function 290: GetCollisionRec() (2 input parameters) +Function 291: GetCollisionRec() (2 input parameters) Name: GetCollisionRec Return type: Rectangle Description: Get collision rectangle for two rectangles collision Param[1]: rec1 (type: Rectangle) Param[2]: rec2 (type: Rectangle) -Function 291: LoadImage() (1 input parameters) +Function 292: LoadImage() (1 input parameters) Name: LoadImage Return type: Image Description: Load image from file into CPU memory (RAM) Param[1]: fileName (type: const char *) -Function 292: LoadImageRaw() (5 input parameters) +Function 293: LoadImageRaw() (5 input parameters) Name: LoadImageRaw Return type: Image Description: Load image from RAW file data @@ -2767,13 +2772,13 @@ Function 292: LoadImageRaw() (5 input parameters) Param[3]: height (type: int) Param[4]: format (type: int) Param[5]: headerSize (type: int) -Function 293: LoadImageAnim() (2 input parameters) +Function 294: LoadImageAnim() (2 input parameters) Name: LoadImageAnim Return type: Image Description: Load image sequence from file (frames appended to image.data) Param[1]: fileName (type: const char *) Param[2]: frames (type: int *) -Function 294: LoadImageAnimFromMemory() (4 input parameters) +Function 295: LoadImageAnimFromMemory() (4 input parameters) Name: LoadImageAnimFromMemory Return type: Image Description: Load image sequence from memory buffer @@ -2781,60 +2786,60 @@ Function 294: LoadImageAnimFromMemory() (4 input parameters) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) Param[4]: frames (type: int *) -Function 295: LoadImageFromMemory() (3 input parameters) +Function 296: LoadImageFromMemory() (3 input parameters) Name: LoadImageFromMemory Return type: Image Description: Load image from memory buffer, fileType refers to extension: i.e. '.png' Param[1]: fileType (type: const char *) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 296: LoadImageFromTexture() (1 input parameters) +Function 297: LoadImageFromTexture() (1 input parameters) Name: LoadImageFromTexture Return type: Image Description: Load image from GPU texture data Param[1]: texture (type: Texture2D) -Function 297: LoadImageFromScreen() (0 input parameters) +Function 298: LoadImageFromScreen() (0 input parameters) Name: LoadImageFromScreen Return type: Image Description: Load image from screen buffer (screenshot) No input parameters -Function 298: IsImageValid() (1 input parameters) +Function 299: IsImageValid() (1 input parameters) Name: IsImageValid Return type: bool Description: Check if an image is valid (data and parameters) Param[1]: image (type: Image) -Function 299: UnloadImage() (1 input parameters) +Function 300: UnloadImage() (1 input parameters) Name: UnloadImage Return type: void Description: Unload image from CPU memory (RAM) Param[1]: image (type: Image) -Function 300: ExportImage() (2 input parameters) +Function 301: ExportImage() (2 input parameters) Name: ExportImage Return type: bool Description: Export image data to file, returns true on success Param[1]: image (type: Image) Param[2]: fileName (type: const char *) -Function 301: ExportImageToMemory() (3 input parameters) +Function 302: ExportImageToMemory() (3 input parameters) Name: ExportImageToMemory Return type: unsigned char * Description: Export image to memory buffer, memory must be MemFree() Param[1]: image (type: Image) Param[2]: fileType (type: const char *) Param[3]: fileSize (type: int *) -Function 302: ExportImageAsCode() (2 input parameters) +Function 303: ExportImageAsCode() (2 input parameters) Name: ExportImageAsCode Return type: bool Description: Export image as code file defining an array of bytes, returns true on success Param[1]: image (type: Image) Param[2]: fileName (type: const char *) -Function 303: GenImageColor() (3 input parameters) +Function 304: GenImageColor() (3 input parameters) Name: GenImageColor Return type: Image Description: Generate image: plain color Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: color (type: Color) -Function 304: GenImageGradientLinear() (5 input parameters) +Function 305: GenImageGradientLinear() (5 input parameters) Name: GenImageGradientLinear Return type: Image Description: Generate image: linear gradient, direction in degrees [0..360], 0=Vertical gradient @@ -2843,7 +2848,7 @@ Function 304: GenImageGradientLinear() (5 input parameters) Param[3]: direction (type: int) Param[4]: start (type: Color) Param[5]: end (type: Color) -Function 305: GenImageGradientRadial() (5 input parameters) +Function 306: GenImageGradientRadial() (5 input parameters) Name: GenImageGradientRadial Return type: Image Description: Generate image: radial gradient @@ -2852,7 +2857,7 @@ Function 305: GenImageGradientRadial() (5 input parameters) Param[3]: density (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 306: GenImageGradientSquare() (5 input parameters) +Function 307: GenImageGradientSquare() (5 input parameters) Name: GenImageGradientSquare Return type: Image Description: Generate image: square gradient @@ -2861,7 +2866,7 @@ Function 306: GenImageGradientSquare() (5 input parameters) Param[3]: density (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 307: GenImageChecked() (6 input parameters) +Function 308: GenImageChecked() (6 input parameters) Name: GenImageChecked Return type: Image Description: Generate image: checked @@ -2871,14 +2876,14 @@ Function 307: GenImageChecked() (6 input parameters) Param[4]: checksY (type: int) Param[5]: col1 (type: Color) Param[6]: col2 (type: Color) -Function 308: GenImageWhiteNoise() (3 input parameters) +Function 309: GenImageWhiteNoise() (3 input parameters) Name: GenImageWhiteNoise Return type: Image Description: Generate image: white noise Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: factor (type: float) -Function 309: GenImagePerlinNoise() (5 input parameters) +Function 310: GenImagePerlinNoise() (5 input parameters) Name: GenImagePerlinNoise Return type: Image Description: Generate image: perlin noise @@ -2887,45 +2892,45 @@ Function 309: GenImagePerlinNoise() (5 input parameters) Param[3]: offsetX (type: int) Param[4]: offsetY (type: int) Param[5]: scale (type: float) -Function 310: GenImageCellular() (3 input parameters) +Function 311: GenImageCellular() (3 input parameters) Name: GenImageCellular Return type: Image Description: Generate image: cellular algorithm, bigger tileSize means bigger cells Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: tileSize (type: int) -Function 311: GenImageText() (3 input parameters) +Function 312: GenImageText() (3 input parameters) Name: GenImageText Return type: Image Description: Generate image: grayscale image from text data Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: text (type: const char *) -Function 312: ImageCopy() (1 input parameters) +Function 313: ImageCopy() (1 input parameters) Name: ImageCopy Return type: Image Description: Create an image duplicate (useful for transformations) Param[1]: image (type: Image) -Function 313: ImageFromImage() (2 input parameters) +Function 314: ImageFromImage() (2 input parameters) Name: ImageFromImage Return type: Image Description: Create an image from another image piece Param[1]: image (type: Image) Param[2]: rec (type: Rectangle) -Function 314: ImageFromChannel() (2 input parameters) +Function 315: ImageFromChannel() (2 input parameters) Name: ImageFromChannel Return type: Image Description: Create an image from a selected channel of another image (GRAYSCALE) Param[1]: image (type: Image) Param[2]: selectedChannel (type: int) -Function 315: ImageText() (3 input parameters) +Function 316: ImageText() (3 input parameters) Name: ImageText Return type: Image Description: Create an image from text (default font) Param[1]: text (type: const char *) Param[2]: fontSize (type: int) Param[3]: color (type: Color) -Function 316: ImageTextEx() (5 input parameters) +Function 317: ImageTextEx() (5 input parameters) Name: ImageTextEx Return type: Image Description: Create an image from text (custom sprite font) @@ -2934,76 +2939,76 @@ Function 316: ImageTextEx() (5 input parameters) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) Param[5]: tint (type: Color) -Function 317: ImageFormat() (2 input parameters) +Function 318: ImageFormat() (2 input parameters) Name: ImageFormat Return type: void Description: Convert image data to desired format Param[1]: image (type: Image *) Param[2]: newFormat (type: int) -Function 318: ImageToPOT() (2 input parameters) +Function 319: ImageToPOT() (2 input parameters) Name: ImageToPOT Return type: void Description: Convert image to POT (power-of-two) Param[1]: image (type: Image *) Param[2]: fill (type: Color) -Function 319: ImageCrop() (2 input parameters) +Function 320: ImageCrop() (2 input parameters) Name: ImageCrop Return type: void Description: Crop an image to a defined rectangle Param[1]: image (type: Image *) Param[2]: crop (type: Rectangle) -Function 320: ImageAlphaCrop() (2 input parameters) +Function 321: ImageAlphaCrop() (2 input parameters) Name: ImageAlphaCrop Return type: void Description: Crop image depending on alpha value Param[1]: image (type: Image *) Param[2]: threshold (type: float) -Function 321: ImageAlphaClear() (3 input parameters) +Function 322: ImageAlphaClear() (3 input parameters) Name: ImageAlphaClear Return type: void Description: Clear alpha channel to desired color Param[1]: image (type: Image *) Param[2]: color (type: Color) Param[3]: threshold (type: float) -Function 322: ImageAlphaMask() (2 input parameters) +Function 323: ImageAlphaMask() (2 input parameters) Name: ImageAlphaMask Return type: void Description: Apply alpha mask to image Param[1]: image (type: Image *) Param[2]: alphaMask (type: Image) -Function 323: ImageAlphaPremultiply() (1 input parameters) +Function 324: ImageAlphaPremultiply() (1 input parameters) Name: ImageAlphaPremultiply Return type: void Description: Premultiply alpha channel Param[1]: image (type: Image *) -Function 324: ImageBlurGaussian() (2 input parameters) +Function 325: ImageBlurGaussian() (2 input parameters) Name: ImageBlurGaussian Return type: void Description: Apply Gaussian blur using a box blur approximation Param[1]: image (type: Image *) Param[2]: blurSize (type: int) -Function 325: ImageKernelConvolution() (3 input parameters) +Function 326: ImageKernelConvolution() (3 input parameters) Name: ImageKernelConvolution Return type: void Description: Apply custom square convolution kernel to image Param[1]: image (type: Image *) Param[2]: kernel (type: const float *) Param[3]: kernelSize (type: int) -Function 326: ImageResize() (3 input parameters) +Function 327: ImageResize() (3 input parameters) Name: ImageResize Return type: void Description: Resize image (Bicubic scaling algorithm) Param[1]: image (type: Image *) Param[2]: newWidth (type: int) Param[3]: newHeight (type: int) -Function 327: ImageResizeNN() (3 input parameters) +Function 328: ImageResizeNN() (3 input parameters) Name: ImageResizeNN Return type: void Description: Resize image (Nearest-Neighbor scaling algorithm) Param[1]: image (type: Image *) Param[2]: newWidth (type: int) Param[3]: newHeight (type: int) -Function 328: ImageResizeCanvas() (6 input parameters) +Function 329: ImageResizeCanvas() (6 input parameters) Name: ImageResizeCanvas Return type: void Description: Resize canvas and fill with color @@ -3013,12 +3018,12 @@ Function 328: ImageResizeCanvas() (6 input parameters) Param[4]: offsetX (type: int) Param[5]: offsetY (type: int) Param[6]: fill (type: Color) -Function 329: ImageMipmaps() (1 input parameters) +Function 330: ImageMipmaps() (1 input parameters) Name: ImageMipmaps Return type: void Description: Compute all mipmap levels for a provided image Param[1]: image (type: Image *) -Function 330: ImageDither() (5 input parameters) +Function 331: ImageDither() (5 input parameters) Name: ImageDither Return type: void Description: Dither image data to 16bpp or lower (Floyd-Steinberg dithering) @@ -3027,109 +3032,109 @@ Function 330: ImageDither() (5 input parameters) Param[3]: gBpp (type: int) Param[4]: bBpp (type: int) Param[5]: aBpp (type: int) -Function 331: ImageFlipVertical() (1 input parameters) +Function 332: ImageFlipVertical() (1 input parameters) Name: ImageFlipVertical Return type: void Description: Flip image vertically Param[1]: image (type: Image *) -Function 332: ImageFlipHorizontal() (1 input parameters) +Function 333: ImageFlipHorizontal() (1 input parameters) Name: ImageFlipHorizontal Return type: void Description: Flip image horizontally Param[1]: image (type: Image *) -Function 333: ImageRotate() (2 input parameters) +Function 334: ImageRotate() (2 input parameters) Name: ImageRotate Return type: void Description: Rotate image by input angle in degrees (-359 to 359) Param[1]: image (type: Image *) Param[2]: degrees (type: int) -Function 334: ImageRotateCW() (1 input parameters) +Function 335: ImageRotateCW() (1 input parameters) Name: ImageRotateCW Return type: void Description: Rotate image clockwise 90deg Param[1]: image (type: Image *) -Function 335: ImageRotateCCW() (1 input parameters) +Function 336: ImageRotateCCW() (1 input parameters) Name: ImageRotateCCW Return type: void Description: Rotate image counter-clockwise 90deg Param[1]: image (type: Image *) -Function 336: ImageColorTint() (2 input parameters) +Function 337: ImageColorTint() (2 input parameters) Name: ImageColorTint Return type: void Description: Modify image color: tint Param[1]: image (type: Image *) Param[2]: color (type: Color) -Function 337: ImageColorInvert() (1 input parameters) +Function 338: ImageColorInvert() (1 input parameters) Name: ImageColorInvert Return type: void Description: Modify image color: invert Param[1]: image (type: Image *) -Function 338: ImageColorGrayscale() (1 input parameters) +Function 339: ImageColorGrayscale() (1 input parameters) Name: ImageColorGrayscale Return type: void Description: Modify image color: grayscale Param[1]: image (type: Image *) -Function 339: ImageColorContrast() (2 input parameters) +Function 340: ImageColorContrast() (2 input parameters) Name: ImageColorContrast Return type: void Description: Modify image color: contrast (-100 to 100) Param[1]: image (type: Image *) Param[2]: contrast (type: int) -Function 340: ImageColorBrightness() (2 input parameters) +Function 341: ImageColorBrightness() (2 input parameters) Name: ImageColorBrightness Return type: void Description: Modify image color: brightness (-255 to 255) Param[1]: image (type: Image *) Param[2]: brightness (type: int) -Function 341: ImageColorReplace() (3 input parameters) +Function 342: ImageColorReplace() (3 input parameters) Name: ImageColorReplace Return type: void Description: Modify image color: replace color Param[1]: image (type: Image *) Param[2]: color (type: Color) Param[3]: replace (type: Color) -Function 342: LoadImageColors() (1 input parameters) +Function 343: LoadImageColors() (1 input parameters) Name: LoadImageColors Return type: Color * Description: Load color data from image as a Color array (RGBA - 32bit) Param[1]: image (type: Image) -Function 343: LoadImagePalette() (3 input parameters) +Function 344: LoadImagePalette() (3 input parameters) Name: LoadImagePalette Return type: Color * Description: Load colors palette from image as a Color array (RGBA - 32bit) Param[1]: image (type: Image) Param[2]: maxPaletteSize (type: int) Param[3]: colorCount (type: int *) -Function 344: UnloadImageColors() (1 input parameters) +Function 345: UnloadImageColors() (1 input parameters) Name: UnloadImageColors Return type: void Description: Unload color data loaded with LoadImageColors() Param[1]: colors (type: Color *) -Function 345: UnloadImagePalette() (1 input parameters) +Function 346: UnloadImagePalette() (1 input parameters) Name: UnloadImagePalette Return type: void Description: Unload colors palette loaded with LoadImagePalette() Param[1]: colors (type: Color *) -Function 346: GetImageAlphaBorder() (2 input parameters) +Function 347: GetImageAlphaBorder() (2 input parameters) Name: GetImageAlphaBorder Return type: Rectangle Description: Get image alpha border rectangle Param[1]: image (type: Image) Param[2]: threshold (type: float) -Function 347: GetImageColor() (3 input parameters) +Function 348: GetImageColor() (3 input parameters) Name: GetImageColor Return type: Color Description: Get image pixel color at (x, y) position Param[1]: image (type: Image) Param[2]: x (type: int) Param[3]: y (type: int) -Function 348: ImageClearBackground() (2 input parameters) +Function 349: ImageClearBackground() (2 input parameters) Name: ImageClearBackground Return type: void - Description: Clear image background with given color + Description: Clear image background with provided color Param[1]: dst (type: Image *) Param[2]: color (type: Color) -Function 349: ImageDrawPixel() (4 input parameters) +Function 350: ImageDrawPixel() (4 input parameters) Name: ImageDrawPixel Return type: void Description: Draw pixel within an image @@ -3137,14 +3142,14 @@ Function 349: ImageDrawPixel() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: color (type: Color) -Function 350: ImageDrawPixelV() (3 input parameters) +Function 351: ImageDrawPixelV() (3 input parameters) Name: ImageDrawPixelV Return type: void Description: Draw pixel within an image (Vector version) Param[1]: dst (type: Image *) Param[2]: position (type: Vector2) Param[3]: color (type: Color) -Function 351: ImageDrawLine() (6 input parameters) +Function 352: ImageDrawLine() (6 input parameters) Name: ImageDrawLine Return type: void Description: Draw line within an image @@ -3154,7 +3159,7 @@ Function 351: ImageDrawLine() (6 input parameters) Param[4]: endPosX (type: int) Param[5]: endPosY (type: int) Param[6]: color (type: Color) -Function 352: ImageDrawLineV() (4 input parameters) +Function 353: ImageDrawLineV() (4 input parameters) Name: ImageDrawLineV Return type: void Description: Draw line within an image (Vector version) @@ -3162,7 +3167,7 @@ Function 352: ImageDrawLineV() (4 input parameters) Param[2]: start (type: Vector2) Param[3]: end (type: Vector2) Param[4]: color (type: Color) -Function 353: ImageDrawLineEx() (5 input parameters) +Function 354: ImageDrawLineEx() (5 input parameters) Name: ImageDrawLineEx Return type: void Description: Draw a line defining thickness within an image @@ -3171,7 +3176,7 @@ Function 353: ImageDrawLineEx() (5 input parameters) Param[3]: end (type: Vector2) Param[4]: thick (type: int) Param[5]: color (type: Color) -Function 354: ImageDrawLineStrip() (4 input parameters) +Function 355: ImageDrawLineStrip() (4 input parameters) Name: ImageDrawLineStrip Return type: void Description: Draw a lines sequence within an image @@ -3179,7 +3184,7 @@ Function 354: ImageDrawLineStrip() (4 input parameters) Param[2]: points (type: const Vector2 *) Param[3]: pointCount (type: int) Param[4]: color (type: Color) -Function 355: ImageDrawTriangle() (5 input parameters) +Function 356: ImageDrawTriangle() (5 input parameters) Name: ImageDrawTriangle Return type: void Description: Draw triangle within an image @@ -3188,7 +3193,7 @@ Function 355: ImageDrawTriangle() (5 input parameters) Param[3]: v2 (type: Vector2) Param[4]: v3 (type: Vector2) Param[5]: color (type: Color) -Function 356: ImageDrawTriangleGradient() (7 input parameters) +Function 357: ImageDrawTriangleGradient() (7 input parameters) Name: ImageDrawTriangleGradient Return type: void Description: Draw triangle with interpolated colors within an image @@ -3199,7 +3204,7 @@ Function 356: ImageDrawTriangleGradient() (7 input parameters) Param[5]: c1 (type: Color) Param[6]: c2 (type: Color) Param[7]: c3 (type: Color) -Function 357: ImageDrawTriangleLines() (5 input parameters) +Function 358: ImageDrawTriangleLines() (5 input parameters) Name: ImageDrawTriangleLines Return type: void Description: Draw triangle outline within an image @@ -3208,7 +3213,7 @@ Function 357: ImageDrawTriangleLines() (5 input parameters) Param[3]: v2 (type: Vector2) Param[4]: v3 (type: Vector2) Param[5]: color (type: Color) -Function 358: ImageDrawTriangleFan() (4 input parameters) +Function 359: ImageDrawTriangleFan() (4 input parameters) Name: ImageDrawTriangleFan Return type: void Description: Draw a triangle fan defined by points within an image (first vertex is the center) @@ -3216,7 +3221,7 @@ Function 358: ImageDrawTriangleFan() (4 input parameters) Param[2]: points (type: const Vector2 *) Param[3]: pointCount (type: int) Param[4]: color (type: Color) -Function 359: ImageDrawTriangleStrip() (4 input parameters) +Function 360: ImageDrawTriangleStrip() (4 input parameters) Name: ImageDrawTriangleStrip Return type: void Description: Draw a triangle strip defined by points within an image @@ -3224,7 +3229,7 @@ Function 359: ImageDrawTriangleStrip() (4 input parameters) Param[2]: points (type: const Vector2 *) Param[3]: pointCount (type: int) Param[4]: color (type: Color) -Function 360: ImageDrawRectangle() (6 input parameters) +Function 361: ImageDrawRectangle() (6 input parameters) Name: ImageDrawRectangle Return type: void Description: Draw rectangle within an image @@ -3234,7 +3239,7 @@ Function 360: ImageDrawRectangle() (6 input parameters) Param[4]: width (type: int) Param[5]: height (type: int) Param[6]: color (type: Color) -Function 361: ImageDrawRectangleV() (4 input parameters) +Function 362: ImageDrawRectangleV() (4 input parameters) Name: ImageDrawRectangleV Return type: void Description: Draw rectangle within an image (Vector version) @@ -3242,14 +3247,14 @@ Function 361: ImageDrawRectangleV() (4 input parameters) Param[2]: position (type: Vector2) Param[3]: size (type: Vector2) Param[4]: color (type: Color) -Function 362: ImageDrawRectangleRec() (3 input parameters) +Function 363: ImageDrawRectangleRec() (3 input parameters) Name: ImageDrawRectangleRec Return type: void Description: Draw rectangle within an image Param[1]: dst (type: Image *) Param[2]: rec (type: Rectangle) Param[3]: color (type: Color) -Function 363: ImageDrawRectanglePro() (5 input parameters) +Function 364: ImageDrawRectanglePro() (5 input parameters) Name: ImageDrawRectanglePro Return type: void Description: Draw a color-filled rectangle with pro parameters within and image @@ -3258,7 +3263,7 @@ Function 363: ImageDrawRectanglePro() (5 input parameters) Param[3]: origin (type: Vector2) Param[4]: rotation (type: float) Param[5]: color (type: Color) -Function 364: ImageDrawRectangleLines() (6 input parameters) +Function 365: ImageDrawRectangleLines() (6 input parameters) Name: ImageDrawRectangleLines Return type: void Description: Draw rectangle lines within an image @@ -3268,7 +3273,7 @@ Function 364: ImageDrawRectangleLines() (6 input parameters) Param[4]: width (type: int) Param[5]: height (type: int) Param[6]: color (type: Color) -Function 365: ImageDrawRectangleLinesEx() (4 input parameters) +Function 366: ImageDrawRectangleLinesEx() (4 input parameters) Name: ImageDrawRectangleLinesEx Return type: void Description: Draw rectangle lines within an image with line thickness @@ -3276,7 +3281,7 @@ Function 365: ImageDrawRectangleLinesEx() (4 input parameters) Param[2]: rec (type: Rectangle) Param[3]: thick (type: int) Param[4]: color (type: Color) -Function 366: ImageDrawRectangleGradientEx() (6 input parameters) +Function 367: ImageDrawRectangleGradientEx() (6 input parameters) Name: ImageDrawRectangleGradientEx Return type: void Description: Draw rectangle with gradient colors within an image, counter-clockwise color order @@ -3286,7 +3291,7 @@ Function 366: ImageDrawRectangleGradientEx() (6 input parameters) Param[4]: col2 (type: Color) Param[5]: col3 (type: Color) Param[6]: col4 (type: Color) -Function 367: ImageDrawCircle() (5 input parameters) +Function 368: ImageDrawCircle() (5 input parameters) Name: ImageDrawCircle Return type: void Description: Draw a filled circle within an image @@ -3295,7 +3300,7 @@ Function 367: ImageDrawCircle() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 368: ImageDrawCircleV() (4 input parameters) +Function 369: ImageDrawCircleV() (4 input parameters) Name: ImageDrawCircleV Return type: void Description: Draw a filled circle within an image (Vector version) @@ -3303,7 +3308,7 @@ Function 368: ImageDrawCircleV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 369: ImageDrawCircleLines() (5 input parameters) +Function 370: ImageDrawCircleLines() (5 input parameters) Name: ImageDrawCircleLines Return type: void Description: Draw circle outline within an image @@ -3312,7 +3317,7 @@ Function 369: ImageDrawCircleLines() (5 input parameters) Param[3]: centerY (type: int) Param[4]: radius (type: int) Param[5]: color (type: Color) -Function 370: ImageDrawCircleLinesV() (4 input parameters) +Function 371: ImageDrawCircleLinesV() (4 input parameters) Name: ImageDrawCircleLinesV Return type: void Description: Draw circle outline within an image (Vector version) @@ -3320,7 +3325,7 @@ Function 370: ImageDrawCircleLinesV() (4 input parameters) Param[2]: center (type: Vector2) Param[3]: radius (type: int) Param[4]: color (type: Color) -Function 371: ImageDrawCircleGradient() (5 input parameters) +Function 372: ImageDrawCircleGradient() (5 input parameters) Name: ImageDrawCircleGradient Return type: void Description: Draw a gradient-filled circle within an image @@ -3329,7 +3334,7 @@ Function 371: ImageDrawCircleGradient() (5 input parameters) Param[3]: radius (type: float) Param[4]: inner (type: Color) Param[5]: outer (type: Color) -Function 372: ImageDrawImage() (5 input parameters) +Function 373: ImageDrawImage() (5 input parameters) Name: ImageDrawImage Return type: void Description: Draw an image within an image @@ -3338,7 +3343,7 @@ Function 372: ImageDrawImage() (5 input parameters) Param[3]: posX (type: int) Param[4]: posY (type: int) Param[5]: tint (type: Color) -Function 373: ImageDrawImageEx() (6 input parameters) +Function 374: ImageDrawImageEx() (6 input parameters) Name: ImageDrawImageEx Return type: void Description: Draw an image with scaling and rotation within an image @@ -3348,7 +3353,7 @@ Function 373: ImageDrawImageEx() (6 input parameters) Param[4]: rotation (type: float) Param[5]: scale (type: float) Param[6]: tint (type: Color) -Function 374: ImageDrawImageRec() (5 input parameters) +Function 375: ImageDrawImageRec() (5 input parameters) Name: ImageDrawImageRec Return type: void Description: Draw a part of an image defined by a rectangle within an image @@ -3357,7 +3362,7 @@ Function 374: ImageDrawImageRec() (5 input parameters) Param[3]: srcRec (type: Rectangle) Param[4]: position (type: Vector2) Param[5]: tint (type: Color) -Function 375: ImageDrawImagePro() (7 input parameters) +Function 376: ImageDrawImagePro() (7 input parameters) Name: ImageDrawImagePro Return type: void Description: Draw a part of an image defined by a rectangle into destination rectangle, with scaling and rotation, within an image @@ -3368,7 +3373,7 @@ Function 375: ImageDrawImagePro() (7 input parameters) Param[5]: origin (type: Vector2) Param[6]: rotation (type: float) Param[7]: tint (type: Color) -Function 376: ImageDrawText() (6 input parameters) +Function 377: ImageDrawText() (6 input parameters) Name: ImageDrawText Return type: void Description: Draw text (using default font) within an image (destination) @@ -3378,7 +3383,7 @@ Function 376: ImageDrawText() (6 input parameters) Param[4]: posY (type: int) Param[5]: fontSize (type: int) Param[6]: color (type: Color) -Function 377: ImageDrawTextEx() (7 input parameters) +Function 378: ImageDrawTextEx() (7 input parameters) Name: ImageDrawTextEx Return type: void Description: Draw text (custom sprite font) within an image (destination) @@ -3389,7 +3394,7 @@ Function 377: ImageDrawTextEx() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 378: ImageDrawTextPro() (9 input parameters) +Function 379: ImageDrawTextPro() (9 input parameters) Name: ImageDrawTextPro Return type: void Description: Draw text using Font and pro parameters (rotation) @@ -3402,79 +3407,79 @@ Function 378: ImageDrawTextPro() (9 input parameters) Param[7]: fontSize (type: float) Param[8]: spacing (type: float) Param[9]: tint (type: Color) -Function 379: LoadTexture() (1 input parameters) +Function 380: LoadTexture() (1 input parameters) Name: LoadTexture Return type: Texture2D Description: Load texture from file into GPU memory (VRAM) Param[1]: fileName (type: const char *) -Function 380: LoadTextureFromImage() (1 input parameters) +Function 381: LoadTextureFromImage() (1 input parameters) Name: LoadTextureFromImage Return type: Texture2D Description: Load texture from image data Param[1]: image (type: Image) -Function 381: LoadTextureCubemap() (2 input parameters) +Function 382: LoadTextureCubemap() (2 input parameters) Name: LoadTextureCubemap Return type: TextureCubemap Description: Load cubemap from image, multiple image cubemap layouts supported Param[1]: image (type: Image) Param[2]: layout (type: int) -Function 382: LoadRenderTexture() (2 input parameters) +Function 383: LoadRenderTexture() (2 input parameters) Name: LoadRenderTexture Return type: RenderTexture2D Description: Load texture for rendering (framebuffer) Param[1]: width (type: int) Param[2]: height (type: int) -Function 383: IsTextureValid() (1 input parameters) +Function 384: IsTextureValid() (1 input parameters) Name: IsTextureValid Return type: bool Description: Check if texture is valid (loaded in GPU) Param[1]: texture (type: Texture2D) -Function 384: UnloadTexture() (1 input parameters) +Function 385: UnloadTexture() (1 input parameters) Name: UnloadTexture Return type: void Description: Unload texture from GPU memory (VRAM) Param[1]: texture (type: Texture2D) -Function 385: IsRenderTextureValid() (1 input parameters) +Function 386: IsRenderTextureValid() (1 input parameters) Name: IsRenderTextureValid Return type: bool Description: Check if render texture is valid (loaded in GPU) Param[1]: target (type: RenderTexture2D) -Function 386: UnloadRenderTexture() (1 input parameters) +Function 387: UnloadRenderTexture() (1 input parameters) Name: UnloadRenderTexture Return type: void Description: Unload render texture from GPU memory (VRAM) Param[1]: target (type: RenderTexture2D) -Function 387: UpdateTexture() (2 input parameters) +Function 388: UpdateTexture() (2 input parameters) Name: UpdateTexture Return type: void Description: Update GPU texture with new data (pixels should be able to fill texture) Param[1]: texture (type: Texture2D) Param[2]: pixels (type: const void *) -Function 388: UpdateTextureRec() (3 input parameters) +Function 389: UpdateTextureRec() (3 input parameters) Name: UpdateTextureRec Return type: void Description: Update GPU texture rectangle with new data (pixels and rec should fit in texture) Param[1]: texture (type: Texture2D) Param[2]: rec (type: Rectangle) Param[3]: pixels (type: const void *) -Function 389: GenTextureMipmaps() (1 input parameters) +Function 390: GenTextureMipmaps() (1 input parameters) Name: GenTextureMipmaps Return type: void Description: Generate GPU mipmaps for a texture Param[1]: texture (type: Texture2D *) -Function 390: SetTextureFilter() (2 input parameters) +Function 391: SetTextureFilter() (2 input parameters) Name: SetTextureFilter Return type: void Description: Set texture scaling filter mode Param[1]: texture (type: Texture2D) Param[2]: filter (type: int) -Function 391: SetTextureWrap() (2 input parameters) +Function 392: SetTextureWrap() (2 input parameters) Name: SetTextureWrap Return type: void Description: Set texture wrapping mode Param[1]: texture (type: Texture2D) Param[2]: wrap (type: int) -Function 392: DrawTexture() (4 input parameters) +Function 393: DrawTexture() (4 input parameters) Name: DrawTexture Return type: void Description: Draw a Texture2D @@ -3482,14 +3487,14 @@ Function 392: DrawTexture() (4 input parameters) Param[2]: posX (type: int) Param[3]: posY (type: int) Param[4]: tint (type: Color) -Function 393: DrawTextureV() (3 input parameters) +Function 394: DrawTextureV() (3 input parameters) Name: DrawTextureV Return type: void Description: Draw a Texture2D with position defined as Vector2 Param[1]: texture (type: Texture2D) Param[2]: position (type: Vector2) Param[3]: tint (type: Color) -Function 394: DrawTextureEx() (5 input parameters) +Function 395: DrawTextureEx() (5 input parameters) Name: DrawTextureEx Return type: void Description: Draw a Texture2D with rotation and scale @@ -3498,7 +3503,7 @@ Function 394: DrawTextureEx() (5 input parameters) Param[3]: rotation (type: float) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 395: DrawTextureRec() (4 input parameters) +Function 396: DrawTextureRec() (4 input parameters) Name: DrawTextureRec Return type: void Description: Draw a part of a texture defined by a rectangle @@ -3506,7 +3511,7 @@ Function 395: DrawTextureRec() (4 input parameters) Param[2]: rec (type: Rectangle) Param[3]: position (type: Vector2) Param[4]: tint (type: Color) -Function 396: DrawTexturePro() (6 input parameters) +Function 397: DrawTexturePro() (6 input parameters) Name: DrawTexturePro Return type: void Description: Draw a part of a texture defined by a source rectangle to destination rectangle, with scaling and rotation @@ -3516,7 +3521,7 @@ Function 396: DrawTexturePro() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 397: DrawTextureNPatch() (6 input parameters) +Function 398: DrawTextureNPatch() (6 input parameters) Name: DrawTextureNPatch Return type: void Description: Draw a texture (or part of it) that stretches or shrinks nicely @@ -3526,119 +3531,119 @@ Function 397: DrawTextureNPatch() (6 input parameters) Param[4]: origin (type: Vector2) Param[5]: rotation (type: float) Param[6]: tint (type: Color) -Function 398: ColorIsEqual() (2 input parameters) +Function 399: ColorIsEqual() (2 input parameters) Name: ColorIsEqual Return type: bool Description: Check if two colors are equal Param[1]: col1 (type: Color) Param[2]: col2 (type: Color) -Function 399: Fade() (2 input parameters) +Function 400: Fade() (2 input parameters) Name: Fade Return type: Color Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f Param[1]: color (type: Color) Param[2]: alpha (type: float) -Function 400: ColorToInt() (1 input parameters) +Function 401: ColorToInt() (1 input parameters) Name: ColorToInt Return type: int Description: Get hexadecimal value for a Color (0xRRGGBBAA) Param[1]: color (type: Color) -Function 401: ColorNormalize() (1 input parameters) +Function 402: ColorNormalize() (1 input parameters) Name: ColorNormalize Return type: Vector4 Description: Get Color normalized as float [0..1] Param[1]: color (type: Color) -Function 402: ColorFromNormalized() (1 input parameters) +Function 403: ColorFromNormalized() (1 input parameters) Name: ColorFromNormalized Return type: Color Description: Get Color from normalized values [0..1] Param[1]: normalized (type: Vector4) -Function 403: ColorToHSV() (1 input parameters) +Function 404: ColorToHSV() (1 input parameters) Name: ColorToHSV Return type: Vector3 Description: Get HSV values for a Color, hue [0..360], saturation/value [0..1] Param[1]: color (type: Color) -Function 404: ColorFromHSV() (3 input parameters) +Function 405: ColorFromHSV() (3 input parameters) Name: ColorFromHSV Return type: Color Description: Get a Color from HSV values, hue [0..360], saturation/value [0..1] Param[1]: hue (type: float) Param[2]: saturation (type: float) Param[3]: value (type: float) -Function 405: ColorTint() (2 input parameters) +Function 406: ColorTint() (2 input parameters) Name: ColorTint Return type: Color Description: Get color multiplied with another color Param[1]: color (type: Color) Param[2]: tint (type: Color) -Function 406: ColorBrightness() (2 input parameters) +Function 407: ColorBrightness() (2 input parameters) Name: ColorBrightness Return type: Color Description: Get color with brightness correction, brightness factor goes from -1.0f to 1.0f Param[1]: color (type: Color) Param[2]: factor (type: float) -Function 407: ColorContrast() (2 input parameters) +Function 408: ColorContrast() (2 input parameters) Name: ColorContrast Return type: Color Description: Get color with contrast correction, contrast values between -1.0f and 1.0f Param[1]: color (type: Color) Param[2]: contrast (type: float) -Function 408: ColorAlpha() (2 input parameters) +Function 409: ColorAlpha() (2 input parameters) Name: ColorAlpha Return type: Color Description: Get color with alpha applied, alpha goes from 0.0f to 1.0f Param[1]: color (type: Color) Param[2]: alpha (type: float) -Function 409: ColorAlphaBlend() (3 input parameters) +Function 410: ColorAlphaBlend() (3 input parameters) Name: ColorAlphaBlend Return type: Color Description: Get src alpha-blended into dst color with tint Param[1]: dst (type: Color) Param[2]: src (type: Color) Param[3]: tint (type: Color) -Function 410: ColorLerp() (3 input parameters) +Function 411: ColorLerp() (3 input parameters) Name: ColorLerp Return type: Color Description: Get color lerp interpolation between two colors, factor [0.0f..1.0f] Param[1]: color1 (type: Color) Param[2]: color2 (type: Color) Param[3]: factor (type: float) -Function 411: GetColor() (1 input parameters) +Function 412: GetColor() (1 input parameters) Name: GetColor Return type: Color Description: Get Color structure from hexadecimal value Param[1]: hexValue (type: unsigned int) -Function 412: GetPixelColor() (2 input parameters) +Function 413: GetPixelColor() (2 input parameters) Name: GetPixelColor Return type: Color Description: Get Color from a source pixel pointer of certain format Param[1]: srcPtr (type: const void *) Param[2]: format (type: int) -Function 413: SetPixelColor() (3 input parameters) +Function 414: SetPixelColor() (3 input parameters) Name: SetPixelColor Return type: void Description: Set color formatted into destination pixel pointer Param[1]: dstPtr (type: void *) Param[2]: color (type: Color) Param[3]: format (type: int) -Function 414: GetPixelDataSize() (3 input parameters) +Function 415: GetPixelDataSize() (3 input parameters) Name: GetPixelDataSize Return type: int Description: Get pixel data size in bytes for certain format Param[1]: width (type: int) Param[2]: height (type: int) Param[3]: format (type: int) -Function 415: GetFontDefault() (0 input parameters) +Function 416: GetFontDefault() (0 input parameters) Name: GetFontDefault Return type: Font Description: Get the default Font No input parameters -Function 416: LoadFont() (1 input parameters) +Function 417: LoadFont() (1 input parameters) Name: LoadFont Return type: Font Description: Load font from file into GPU memory (VRAM) Param[1]: fileName (type: const char *) -Function 417: LoadFontEx() (4 input parameters) +Function 418: LoadFontEx() (4 input parameters) Name: LoadFontEx Return type: Font Description: Load font from file with defined codepoints and generation size, use NULL for codepoints and 0 for codepointCount to load the default character set, font size is provided in pixels height @@ -3646,14 +3651,14 @@ Function 417: LoadFontEx() (4 input parameters) Param[2]: fontSize (type: int) Param[3]: codepoints (type: const int *) Param[4]: codepointCount (type: int) -Function 418: LoadFontFromImage() (3 input parameters) +Function 419: LoadFontFromImage() (3 input parameters) Name: LoadFontFromImage Return type: Font Description: Load font from Image (XNA style) Param[1]: image (type: Image) Param[2]: key (type: Color) Param[3]: firstChar (type: int) -Function 419: LoadFontFromMemory() (6 input parameters) +Function 420: LoadFontFromMemory() (6 input parameters) Name: LoadFontFromMemory Return type: Font Description: Load font from memory buffer, fileType refers to extension: i.e. '.ttf' @@ -3663,12 +3668,12 @@ Function 419: LoadFontFromMemory() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: codepoints (type: const int *) Param[6]: codepointCount (type: int) -Function 420: IsFontValid() (1 input parameters) +Function 421: IsFontValid() (1 input parameters) Name: IsFontValid Return type: bool Description: Check if font is valid (font data loaded, WARNING: GPU texture not checked) Param[1]: font (type: Font) -Function 421: LoadFontData() (7 input parameters) +Function 422: LoadFontData() (7 input parameters) Name: LoadFontData Return type: GlyphInfo * Description: Load font data for further use @@ -3679,7 +3684,7 @@ Function 421: LoadFontData() (7 input parameters) Param[5]: codepointCount (type: int) Param[6]: type (type: int) Param[7]: glyphCount (type: int *) -Function 422: GenImageFontAtlas() (6 input parameters) +Function 423: GenImageFontAtlas() (6 input parameters) Name: GenImageFontAtlas Return type: Image Description: Generate image font atlas using chars info @@ -3689,30 +3694,30 @@ Function 422: GenImageFontAtlas() (6 input parameters) Param[4]: fontSize (type: int) Param[5]: padding (type: int) Param[6]: packMethod (type: int) -Function 423: UnloadFontData() (2 input parameters) +Function 424: UnloadFontData() (2 input parameters) Name: UnloadFontData Return type: void Description: Unload font chars info data (RAM) Param[1]: glyphs (type: GlyphInfo *) Param[2]: glyphCount (type: int) -Function 424: UnloadFont() (1 input parameters) +Function 425: UnloadFont() (1 input parameters) Name: UnloadFont Return type: void Description: Unload font from GPU memory (VRAM) Param[1]: font (type: Font) -Function 425: ExportFontAsCode() (2 input parameters) +Function 426: ExportFontAsCode() (2 input parameters) Name: ExportFontAsCode Return type: bool Description: Export font as code file, returns true on success Param[1]: font (type: Font) Param[2]: fileName (type: const char *) -Function 426: DrawFPS() (2 input parameters) +Function 427: DrawFPS() (2 input parameters) Name: DrawFPS Return type: void Description: Draw current FPS Param[1]: posX (type: int) Param[2]: posY (type: int) -Function 427: DrawText() (5 input parameters) +Function 428: DrawText() (5 input parameters) Name: DrawText Return type: void Description: Draw text (using default font) @@ -3721,7 +3726,7 @@ Function 427: DrawText() (5 input parameters) Param[3]: posY (type: int) Param[4]: fontSize (type: int) Param[5]: color (type: Color) -Function 428: DrawTextEx() (6 input parameters) +Function 429: DrawTextEx() (6 input parameters) Name: DrawTextEx Return type: void Description: Draw text using font and additional parameters @@ -3731,7 +3736,7 @@ Function 428: DrawTextEx() (6 input parameters) Param[4]: fontSize (type: float) Param[5]: spacing (type: float) Param[6]: tint (type: Color) -Function 429: DrawTextPro() (8 input parameters) +Function 430: DrawTextPro() (8 input parameters) Name: DrawTextPro Return type: void Description: Draw text using Font and pro parameters (rotation) @@ -3743,7 +3748,7 @@ Function 429: DrawTextPro() (8 input parameters) Param[6]: fontSize (type: float) Param[7]: spacing (type: float) Param[8]: tint (type: Color) -Function 430: DrawTextCodepoint() (5 input parameters) +Function 431: DrawTextCodepoint() (5 input parameters) Name: DrawTextCodepoint Return type: void Description: Draw one character (codepoint) @@ -3752,7 +3757,7 @@ Function 430: DrawTextCodepoint() (5 input parameters) Param[3]: position (type: Vector2) Param[4]: fontSize (type: float) Param[5]: tint (type: Color) -Function 431: DrawTextCodepoints() (7 input parameters) +Function 432: DrawTextCodepoints() (7 input parameters) Name: DrawTextCodepoints Return type: void Description: Draw multiple characters (codepoint) @@ -3763,18 +3768,18 @@ Function 431: DrawTextCodepoints() (7 input parameters) Param[5]: fontSize (type: float) Param[6]: spacing (type: float) Param[7]: tint (type: Color) -Function 432: SetTextLineSpacing() (1 input parameters) +Function 433: SetTextLineSpacing() (1 input parameters) Name: SetTextLineSpacing Return type: void Description: Set vertical line spacing when drawing with line-breaks Param[1]: spacing (type: int) -Function 433: MeasureText() (2 input parameters) +Function 434: MeasureText() (2 input parameters) Name: MeasureText Return type: int Description: Measure string width for default font Param[1]: text (type: const char *) Param[2]: fontSize (type: int) -Function 434: MeasureTextEx() (4 input parameters) +Function 435: MeasureTextEx() (4 input parameters) Name: MeasureTextEx Return type: Vector2 Description: Measure string size for Font @@ -3782,7 +3787,7 @@ Function 434: MeasureTextEx() (4 input parameters) Param[2]: text (type: const char *) Param[3]: fontSize (type: float) Param[4]: spacing (type: float) -Function 435: MeasureTextCodepoints() (5 input parameters) +Function 436: MeasureTextCodepoints() (5 input parameters) Name: MeasureTextCodepoints Return type: Vector2 Description: Measure string size for an existing array of codepoints for Font @@ -3791,144 +3796,144 @@ Function 435: MeasureTextCodepoints() (5 input parameters) Param[3]: length (type: int) Param[4]: fontSize (type: float) Param[5]: spacing (type: float) -Function 436: GetGlyphIndex() (2 input parameters) +Function 437: GetGlyphIndex() (2 input parameters) Name: GetGlyphIndex Return type: int Description: Get glyph index position in font for a codepoint (unicode character), fallback to '?' if not found Param[1]: font (type: Font) Param[2]: codepoint (type: int) -Function 437: GetGlyphInfo() (2 input parameters) +Function 438: GetGlyphInfo() (2 input parameters) Name: GetGlyphInfo Return type: GlyphInfo Description: Get glyph font info data for a codepoint (unicode character), fallback to '?' if not found Param[1]: font (type: Font) Param[2]: codepoint (type: int) -Function 438: GetGlyphAtlasRec() (2 input parameters) +Function 439: GetGlyphAtlasRec() (2 input parameters) Name: GetGlyphAtlasRec Return type: Rectangle Description: Get glyph rectangle in font atlas for a codepoint (unicode character), fallback to '?' if not found Param[1]: font (type: Font) Param[2]: codepoint (type: int) -Function 439: LoadUTF8() (2 input parameters) +Function 440: LoadUTF8() (2 input parameters) Name: LoadUTF8 Return type: char * Description: Load UTF-8 text encoded from codepoints array Param[1]: codepoints (type: const int *) Param[2]: length (type: int) -Function 440: UnloadUTF8() (1 input parameters) +Function 441: UnloadUTF8() (1 input parameters) Name: UnloadUTF8 Return type: void Description: Unload UTF-8 text encoded from codepoints array Param[1]: text (type: char *) -Function 441: LoadCodepoints() (2 input parameters) +Function 442: LoadCodepoints() (2 input parameters) Name: LoadCodepoints Return type: int * Description: Load all codepoints from a UTF-8 text string, codepoints count returned by parameter Param[1]: text (type: const char *) Param[2]: count (type: int *) -Function 442: UnloadCodepoints() (1 input parameters) +Function 443: UnloadCodepoints() (1 input parameters) Name: UnloadCodepoints Return type: void Description: Unload codepoints data from memory Param[1]: codepoints (type: int *) -Function 443: GetCodepointCount() (1 input parameters) +Function 444: GetCodepointCount() (1 input parameters) Name: GetCodepointCount Return type: int Description: Get total number of codepoints in a UTF-8 encoded string Param[1]: text (type: const char *) -Function 444: GetCodepoint() (2 input parameters) +Function 445: GetCodepoint() (2 input parameters) Name: GetCodepoint Return type: int Description: Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure Param[1]: text (type: const char *) Param[2]: codepointSize (type: int *) -Function 445: GetCodepointNext() (2 input parameters) +Function 446: GetCodepointNext() (2 input parameters) Name: GetCodepointNext Return type: int Description: Get next codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure Param[1]: text (type: const char *) Param[2]: codepointSize (type: int *) -Function 446: GetCodepointPrevious() (2 input parameters) +Function 447: GetCodepointPrevious() (2 input parameters) Name: GetCodepointPrevious Return type: int Description: Get previous codepoint in a UTF-8 encoded string, 0x3f('?') is returned on failure Param[1]: text (type: const char *) Param[2]: codepointSize (type: int *) -Function 447: CodepointToUTF8() (2 input parameters) +Function 448: CodepointToUTF8() (2 input parameters) Name: CodepointToUTF8 Return type: const char * Description: Encode one codepoint into UTF-8 byte array (array length returned as parameter) Param[1]: codepoint (type: int) Param[2]: utf8Size (type: int *) -Function 448: LoadTextLines() (2 input parameters) +Function 449: LoadTextLines() (2 input parameters) Name: LoadTextLines Return type: char ** Description: Load text as separate lines ('\n') Param[1]: text (type: const char *) Param[2]: count (type: int *) -Function 449: UnloadTextLines() (2 input parameters) +Function 450: UnloadTextLines() (2 input parameters) Name: UnloadTextLines Return type: void Description: Unload text lines Param[1]: text (type: char **) Param[2]: lineCount (type: int) -Function 450: TextCopy() (2 input parameters) +Function 451: TextCopy() (2 input parameters) Name: TextCopy Return type: int Description: Copy one string to another, returns bytes copied Param[1]: dst (type: char *) Param[2]: src (type: const char *) -Function 451: TextIsEqual() (2 input parameters) +Function 452: TextIsEqual() (2 input parameters) Name: TextIsEqual Return type: bool Description: Check if two text strings are equal Param[1]: text1 (type: const char *) Param[2]: text2 (type: const char *) -Function 452: TextLength() (1 input parameters) +Function 453: TextLength() (1 input parameters) Name: TextLength Return type: unsigned int Description: Get text length, checks for '\0' ending Param[1]: text (type: const char *) -Function 453: TextFormat() (2 input parameters) +Function 454: TextFormat() (2 input parameters) Name: TextFormat Return type: const char * Description: Text formatting with variables (sprintf() style) Param[1]: text (type: const char *) Param[2]: args (type: ...) -Function 454: TextSubtext() (3 input parameters) +Function 455: TextSubtext() (3 input parameters) Name: TextSubtext Return type: const char * Description: Get a piece of a text string Param[1]: text (type: const char *) Param[2]: position (type: int) Param[3]: length (type: int) -Function 455: TextRemoveSpaces() (1 input parameters) +Function 456: TextRemoveSpaces() (1 input parameters) Name: TextRemoveSpaces Return type: const char * Description: Remove text spaces, concat words Param[1]: text (type: const char *) -Function 456: GetTextBetween() (3 input parameters) +Function 457: GetTextBetween() (3 input parameters) Name: GetTextBetween Return type: char * Description: Get text between two strings Param[1]: text (type: const char *) Param[2]: begin (type: const char *) Param[3]: end (type: const char *) -Function 457: TextReplace() (3 input parameters) +Function 458: TextReplace() (3 input parameters) Name: TextReplace Return type: char * Description: Replace text string with new string Param[1]: text (type: const char *) Param[2]: search (type: const char *) Param[3]: replacement (type: const char *) -Function 458: TextReplaceAlloc() (3 input parameters) +Function 459: TextReplaceAlloc() (3 input parameters) Name: TextReplaceAlloc Return type: char * Description: Replace text string with new string, memory must be MemFree() Param[1]: text (type: const char *) Param[2]: search (type: const char *) Param[3]: replacement (type: const char *) -Function 459: TextReplaceBetween() (4 input parameters) +Function 460: TextReplaceBetween() (4 input parameters) Name: TextReplaceBetween Return type: char * Description: Replace text between two specific strings @@ -3936,7 +3941,7 @@ Function 459: TextReplaceBetween() (4 input parameters) Param[2]: begin (type: const char *) Param[3]: end (type: const char *) Param[4]: replacement (type: const char *) -Function 460: TextReplaceBetweenAlloc() (4 input parameters) +Function 461: TextReplaceBetweenAlloc() (4 input parameters) Name: TextReplaceBetweenAlloc Return type: char * Description: Replace text between two specific strings, memory must be MemFree() @@ -3944,96 +3949,96 @@ Function 460: TextReplaceBetweenAlloc() (4 input parameters) Param[2]: begin (type: const char *) Param[3]: end (type: const char *) Param[4]: replacement (type: const char *) -Function 461: TextInsert() (3 input parameters) +Function 462: TextInsert() (3 input parameters) Name: TextInsert Return type: char * Description: Insert text in a defined byte position Param[1]: text (type: const char *) Param[2]: insert (type: const char *) Param[3]: position (type: int) -Function 462: TextInsertAlloc() (3 input parameters) +Function 463: TextInsertAlloc() (3 input parameters) Name: TextInsertAlloc Return type: char * Description: Insert text in a defined byte position, memory must be MemFree() Param[1]: text (type: const char *) Param[2]: insert (type: const char *) Param[3]: position (type: int) -Function 463: TextJoin() (3 input parameters) +Function 464: TextJoin() (3 input parameters) Name: TextJoin Return type: char * Description: Join text strings with delimiter Param[1]: textList (type: char **) Param[2]: count (type: int) Param[3]: delimiter (type: const char *) -Function 464: TextSplit() (3 input parameters) +Function 465: TextSplit() (3 input parameters) Name: TextSplit Return type: char ** Description: Split text into multiple strings, using MAX_TEXTSPLIT_COUNT static strings Param[1]: text (type: const char *) Param[2]: delimiter (type: char) Param[3]: count (type: int *) -Function 465: TextAppend() (3 input parameters) +Function 466: TextAppend() (3 input parameters) Name: TextAppend Return type: void Description: Append text at specific position and move cursor Param[1]: text (type: char *) Param[2]: append (type: const char *) Param[3]: position (type: int *) -Function 466: TextFindIndex() (2 input parameters) +Function 467: TextFindIndex() (2 input parameters) Name: TextFindIndex Return type: int Description: Find first text occurrence within a string, -1 if not found Param[1]: text (type: const char *) Param[2]: search (type: const char *) -Function 467: TextToUpper() (1 input parameters) +Function 468: TextToUpper() (1 input parameters) Name: TextToUpper Return type: char * Description: Get upper case version of provided string Param[1]: text (type: const char *) -Function 468: TextToLower() (1 input parameters) +Function 469: TextToLower() (1 input parameters) Name: TextToLower Return type: char * Description: Get lower case version of provided string Param[1]: text (type: const char *) -Function 469: TextToPascal() (1 input parameters) +Function 470: TextToPascal() (1 input parameters) Name: TextToPascal Return type: char * Description: Get Pascal case notation version of provided string Param[1]: text (type: const char *) -Function 470: TextToSnake() (1 input parameters) +Function 471: TextToSnake() (1 input parameters) Name: TextToSnake Return type: char * Description: Get Snake case notation version of provided string Param[1]: text (type: const char *) -Function 471: TextToCamel() (1 input parameters) +Function 472: TextToCamel() (1 input parameters) Name: TextToCamel Return type: char * Description: Get Camel case notation version of provided string Param[1]: text (type: const char *) -Function 472: TextToInteger() (1 input parameters) +Function 473: TextToInteger() (1 input parameters) Name: TextToInteger Return type: int Description: Get integer value from text Param[1]: text (type: const char *) -Function 473: TextToFloat() (1 input parameters) +Function 474: TextToFloat() (1 input parameters) Name: TextToFloat Return type: float Description: Get float value from text Param[1]: text (type: const char *) -Function 474: DrawLine3D() (3 input parameters) +Function 475: DrawLine3D() (3 input parameters) Name: DrawLine3D Return type: void Description: Draw a line in 3D world space Param[1]: startPos (type: Vector3) Param[2]: endPos (type: Vector3) Param[3]: color (type: Color) -Function 475: DrawPoint3D() (2 input parameters) +Function 476: DrawPoint3D() (2 input parameters) Name: DrawPoint3D Return type: void Description: Draw a point in 3D space, actually a small line Param[1]: position (type: Vector3) Param[2]: color (type: Color) -Function 476: DrawCircle3D() (5 input parameters) +Function 477: DrawCircle3D() (5 input parameters) Name: DrawCircle3D Return type: void Description: Draw a circle in 3D world space @@ -4042,7 +4047,7 @@ Function 476: DrawCircle3D() (5 input parameters) Param[3]: rotationAxis (type: Vector3) Param[4]: rotationAngle (type: float) Param[5]: color (type: Color) -Function 477: DrawTriangle3D() (4 input parameters) +Function 478: DrawTriangle3D() (4 input parameters) Name: DrawTriangle3D Return type: void Description: Draw a color-filled triangle, counter-clockwise vertex order @@ -4050,14 +4055,14 @@ Function 477: DrawTriangle3D() (4 input parameters) Param[2]: v2 (type: Vector3) Param[3]: v3 (type: Vector3) Param[4]: color (type: Color) -Function 478: DrawTriangleStrip3D() (3 input parameters) +Function 479: DrawTriangleStrip3D() (3 input parameters) Name: DrawTriangleStrip3D Return type: void Description: Draw a triangle strip defined by points Param[1]: points (type: const Vector3 *) Param[2]: pointCount (type: int) Param[3]: color (type: Color) -Function 479: DrawCube() (5 input parameters) +Function 480: DrawCube() (5 input parameters) Name: DrawCube Return type: void Description: Draw cube @@ -4066,14 +4071,14 @@ Function 479: DrawCube() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 480: DrawCubeV() (3 input parameters) +Function 481: DrawCubeV() (3 input parameters) Name: DrawCubeV Return type: void Description: Draw cube (Vector version) Param[1]: position (type: Vector3) Param[2]: size (type: Vector3) Param[3]: color (type: Color) -Function 481: DrawCubeWires() (5 input parameters) +Function 482: DrawCubeWires() (5 input parameters) Name: DrawCubeWires Return type: void Description: Draw cube wires @@ -4082,21 +4087,21 @@ Function 481: DrawCubeWires() (5 input parameters) Param[3]: height (type: float) Param[4]: length (type: float) Param[5]: color (type: Color) -Function 482: DrawCubeWiresV() (3 input parameters) +Function 483: DrawCubeWiresV() (3 input parameters) Name: DrawCubeWiresV Return type: void Description: Draw cube wires (Vector version) Param[1]: position (type: Vector3) Param[2]: size (type: Vector3) Param[3]: color (type: Color) -Function 483: DrawSphere() (3 input parameters) +Function 484: DrawSphere() (3 input parameters) Name: DrawSphere Return type: void Description: Draw sphere Param[1]: centerPos (type: Vector3) Param[2]: radius (type: float) Param[3]: color (type: Color) -Function 484: DrawSphereEx() (5 input parameters) +Function 485: DrawSphereEx() (5 input parameters) Name: DrawSphereEx Return type: void Description: Draw sphere with defined rings and slices @@ -4105,7 +4110,7 @@ Function 484: DrawSphereEx() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 485: DrawSphereWires() (5 input parameters) +Function 486: DrawSphereWires() (5 input parameters) Name: DrawSphereWires Return type: void Description: Draw sphere wires @@ -4114,7 +4119,7 @@ Function 485: DrawSphereWires() (5 input parameters) Param[3]: rings (type: int) Param[4]: slices (type: int) Param[5]: color (type: Color) -Function 486: DrawCylinder() (6 input parameters) +Function 487: DrawCylinder() (6 input parameters) Name: DrawCylinder Return type: void Description: Draw a cylinder/cone @@ -4124,7 +4129,7 @@ Function 486: DrawCylinder() (6 input parameters) Param[4]: height (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 487: DrawCylinderEx() (6 input parameters) +Function 488: DrawCylinderEx() (6 input parameters) Name: DrawCylinderEx Return type: void Description: Draw a cylinder with base at startPos and top at endPos @@ -4134,7 +4139,7 @@ Function 487: DrawCylinderEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 488: DrawCylinderWires() (6 input parameters) +Function 489: DrawCylinderWires() (6 input parameters) Name: DrawCylinderWires Return type: void Description: Draw a cylinder/cone wires @@ -4144,7 +4149,7 @@ Function 488: DrawCylinderWires() (6 input parameters) Param[4]: height (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 489: DrawCylinderWiresEx() (6 input parameters) +Function 490: DrawCylinderWiresEx() (6 input parameters) Name: DrawCylinderWiresEx Return type: void Description: Draw a cylinder wires with base at startPos and top at endPos @@ -4154,7 +4159,7 @@ Function 489: DrawCylinderWiresEx() (6 input parameters) Param[4]: endRadius (type: float) Param[5]: sides (type: int) Param[6]: color (type: Color) -Function 490: DrawCapsule() (6 input parameters) +Function 491: DrawCapsule() (6 input parameters) Name: DrawCapsule Return type: void Description: Draw a capsule with the center of its sphere caps at startPos and endPos @@ -4164,7 +4169,7 @@ Function 490: DrawCapsule() (6 input parameters) Param[4]: rings (type: int) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 491: DrawCapsuleWires() (6 input parameters) +Function 492: DrawCapsuleWires() (6 input parameters) Name: DrawCapsuleWires Return type: void Description: Draw capsule wireframe with the center of its sphere caps at startPos and endPos @@ -4174,51 +4179,51 @@ Function 491: DrawCapsuleWires() (6 input parameters) Param[4]: rings (type: int) Param[5]: slices (type: int) Param[6]: color (type: Color) -Function 492: DrawPlane() (3 input parameters) +Function 493: DrawPlane() (3 input parameters) Name: DrawPlane Return type: void Description: Draw a plane XZ Param[1]: centerPos (type: Vector3) Param[2]: size (type: Vector2) Param[3]: color (type: Color) -Function 493: DrawRay() (2 input parameters) +Function 494: DrawRay() (2 input parameters) Name: DrawRay Return type: void Description: Draw a ray line Param[1]: ray (type: Ray) Param[2]: color (type: Color) -Function 494: DrawGrid() (2 input parameters) +Function 495: DrawGrid() (2 input parameters) Name: DrawGrid Return type: void Description: Draw a grid (centered at (0, 0, 0)) Param[1]: slices (type: int) Param[2]: spacing (type: float) -Function 495: LoadModel() (1 input parameters) +Function 496: LoadModel() (1 input parameters) Name: LoadModel Return type: Model Description: Load model from files (meshes and materials) Param[1]: fileName (type: const char *) -Function 496: LoadModelFromMesh() (1 input parameters) +Function 497: LoadModelFromMesh() (1 input parameters) Name: LoadModelFromMesh Return type: Model Description: Load model from generated mesh (default material) Param[1]: mesh (type: Mesh) -Function 497: IsModelValid() (1 input parameters) +Function 498: IsModelValid() (1 input parameters) Name: IsModelValid Return type: bool Description: Check if model is valid (loaded in GPU, VAO/VBOs) Param[1]: model (type: Model) -Function 498: UnloadModel() (1 input parameters) +Function 499: UnloadModel() (1 input parameters) Name: UnloadModel Return type: void Description: Unload model (including meshes) from memory (RAM and/or VRAM) Param[1]: model (type: Model) -Function 499: GetModelBoundingBox() (1 input parameters) +Function 500: GetModelBoundingBox() (1 input parameters) Name: GetModelBoundingBox Return type: BoundingBox Description: Compute model bounding box limits (considers all meshes) Param[1]: model (type: Model) -Function 500: DrawModel() (4 input parameters) +Function 501: DrawModel() (4 input parameters) Name: DrawModel Return type: void Description: Draw a model (with texture if set) @@ -4226,7 +4231,7 @@ Function 500: DrawModel() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 501: DrawModelEx() (6 input parameters) +Function 502: DrawModelEx() (6 input parameters) Name: DrawModelEx Return type: void Description: Draw a model with custom transform @@ -4236,7 +4241,7 @@ Function 501: DrawModelEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 502: DrawModelWires() (4 input parameters) +Function 503: DrawModelWires() (4 input parameters) Name: DrawModelWires Return type: void Description: Draw a model wires (with texture if set) @@ -4244,7 +4249,7 @@ Function 502: DrawModelWires() (4 input parameters) Param[2]: position (type: Vector3) Param[3]: scale (type: float) Param[4]: tint (type: Color) -Function 503: DrawModelWiresEx() (6 input parameters) +Function 504: DrawModelWiresEx() (6 input parameters) Name: DrawModelWiresEx Return type: void Description: Draw a model wires with custom transform @@ -4254,13 +4259,13 @@ Function 503: DrawModelWiresEx() (6 input parameters) Param[4]: rotationAngle (type: float) Param[5]: scale (type: Vector3) Param[6]: tint (type: Color) -Function 504: DrawBoundingBox() (2 input parameters) +Function 505: DrawBoundingBox() (2 input parameters) Name: DrawBoundingBox Return type: void Description: Draw bounding box (wires) Param[1]: box (type: BoundingBox) Param[2]: color (type: Color) -Function 505: DrawBillboard() (5 input parameters) +Function 506: DrawBillboard() (5 input parameters) Name: DrawBillboard Return type: void Description: Draw a billboard texture @@ -4269,7 +4274,7 @@ Function 505: DrawBillboard() (5 input parameters) Param[3]: position (type: Vector3) Param[4]: scale (type: float) Param[5]: tint (type: Color) -Function 506: DrawBillboardRec() (6 input parameters) +Function 507: DrawBillboardRec() (6 input parameters) Name: DrawBillboardRec Return type: void Description: Draw a billboard texture defined by rectangle @@ -4279,7 +4284,7 @@ Function 506: DrawBillboardRec() (6 input parameters) Param[4]: position (type: Vector3) Param[5]: size (type: Vector2) Param[6]: tint (type: Color) -Function 507: DrawBillboardPro() (9 input parameters) +Function 508: DrawBillboardPro() (9 input parameters) Name: DrawBillboardPro Return type: void Description: Draw a billboard texture defined by source rectangle with scaling and rotation @@ -4292,13 +4297,13 @@ Function 507: DrawBillboardPro() (9 input parameters) Param[7]: origin (type: Vector2) Param[8]: rotation (type: float) Param[9]: tint (type: Color) -Function 508: UploadMesh() (2 input parameters) +Function 509: UploadMesh() (2 input parameters) Name: UploadMesh Return type: void Description: Upload mesh vertex data in GPU and provide VAO/VBO ids Param[1]: mesh (type: Mesh *) Param[2]: dynamic (type: bool) -Function 509: UpdateMeshBuffer() (5 input parameters) +Function 510: UpdateMeshBuffer() (5 input parameters) Name: UpdateMeshBuffer Return type: void Description: Update mesh vertex data in GPU for a specific buffer index @@ -4307,19 +4312,19 @@ Function 509: UpdateMeshBuffer() (5 input parameters) Param[3]: data (type: const void *) Param[4]: dataSize (type: int) Param[5]: offset (type: int) -Function 510: UnloadMesh() (1 input parameters) +Function 511: UnloadMesh() (1 input parameters) Name: UnloadMesh Return type: void Description: Unload mesh data from CPU and GPU Param[1]: mesh (type: Mesh) -Function 511: DrawMesh() (3 input parameters) +Function 512: DrawMesh() (3 input parameters) Name: DrawMesh Return type: void Description: Draw a 3d mesh with material and transform Param[1]: mesh (type: Mesh) Param[2]: material (type: Material) Param[3]: transform (type: Matrix) -Function 512: DrawMeshInstanced() (4 input parameters) +Function 513: DrawMeshInstanced() (4 input parameters) Name: DrawMeshInstanced Return type: void Description: Draw multiple mesh instances with material and different transforms @@ -4327,35 +4332,35 @@ Function 512: DrawMeshInstanced() (4 input parameters) Param[2]: material (type: Material) Param[3]: transforms (type: const Matrix *) Param[4]: instances (type: int) -Function 513: GetMeshBoundingBox() (1 input parameters) +Function 514: GetMeshBoundingBox() (1 input parameters) Name: GetMeshBoundingBox Return type: BoundingBox Description: Compute mesh bounding box limits Param[1]: mesh (type: Mesh) -Function 514: GenMeshTangents() (1 input parameters) +Function 515: GenMeshTangents() (1 input parameters) Name: GenMeshTangents Return type: void Description: Compute mesh tangents Param[1]: mesh (type: Mesh *) -Function 515: ExportMesh() (2 input parameters) +Function 516: ExportMesh() (2 input parameters) Name: ExportMesh Return type: bool Description: Export mesh data to file, returns true on success Param[1]: mesh (type: Mesh) Param[2]: fileName (type: const char *) -Function 516: ExportMeshAsCode() (2 input parameters) +Function 517: ExportMeshAsCode() (2 input parameters) Name: ExportMeshAsCode Return type: bool Description: Export mesh as code file (.h) defining multiple arrays of vertex attributes Param[1]: mesh (type: Mesh) Param[2]: fileName (type: const char *) -Function 517: GenMeshPoly() (2 input parameters) +Function 518: GenMeshPoly() (2 input parameters) Name: GenMeshPoly Return type: Mesh Description: Generate polygonal mesh Param[1]: sides (type: int) Param[2]: radius (type: float) -Function 518: GenMeshPlane() (4 input parameters) +Function 519: GenMeshPlane() (4 input parameters) Name: GenMeshPlane Return type: Mesh Description: Generate plane mesh (with subdivisions) @@ -4363,42 +4368,42 @@ Function 518: GenMeshPlane() (4 input parameters) Param[2]: length (type: float) Param[3]: resX (type: int) Param[4]: resZ (type: int) -Function 519: GenMeshCube() (3 input parameters) +Function 520: GenMeshCube() (3 input parameters) Name: GenMeshCube Return type: Mesh Description: Generate cuboid mesh Param[1]: width (type: float) Param[2]: height (type: float) Param[3]: length (type: float) -Function 520: GenMeshSphere() (3 input parameters) +Function 521: GenMeshSphere() (3 input parameters) Name: GenMeshSphere Return type: Mesh Description: Generate sphere mesh (standard sphere) Param[1]: radius (type: float) Param[2]: rings (type: int) Param[3]: slices (type: int) -Function 521: GenMeshHemiSphere() (3 input parameters) +Function 522: GenMeshHemiSphere() (3 input parameters) Name: GenMeshHemiSphere Return type: Mesh Description: Generate half-sphere mesh (no bottom cap) Param[1]: radius (type: float) Param[2]: rings (type: int) Param[3]: slices (type: int) -Function 522: GenMeshCylinder() (3 input parameters) +Function 523: GenMeshCylinder() (3 input parameters) Name: GenMeshCylinder Return type: Mesh Description: Generate cylinder mesh Param[1]: radius (type: float) Param[2]: height (type: float) Param[3]: slices (type: int) -Function 523: GenMeshCone() (3 input parameters) +Function 524: GenMeshCone() (3 input parameters) Name: GenMeshCone Return type: Mesh Description: Generate cone/pyramid mesh Param[1]: radius (type: float) Param[2]: height (type: float) Param[3]: slices (type: int) -Function 524: GenMeshTorus() (4 input parameters) +Function 525: GenMeshTorus() (4 input parameters) Name: GenMeshTorus Return type: Mesh Description: Generate torus mesh @@ -4406,7 +4411,7 @@ Function 524: GenMeshTorus() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 525: GenMeshKnot() (4 input parameters) +Function 526: GenMeshKnot() (4 input parameters) Name: GenMeshKnot Return type: Mesh Description: Generate trefoil knot mesh @@ -4414,67 +4419,67 @@ Function 525: GenMeshKnot() (4 input parameters) Param[2]: size (type: float) Param[3]: radSeg (type: int) Param[4]: sides (type: int) -Function 526: GenMeshHeightmap() (2 input parameters) +Function 527: GenMeshHeightmap() (2 input parameters) Name: GenMeshHeightmap Return type: Mesh Description: Generate heightmap mesh from image data Param[1]: heightmap (type: Image) Param[2]: size (type: Vector3) -Function 527: GenMeshCubicmap() (2 input parameters) +Function 528: GenMeshCubicmap() (2 input parameters) Name: GenMeshCubicmap Return type: Mesh Description: Generate cubes-based map mesh from image data Param[1]: cubicmap (type: Image) Param[2]: cubeSize (type: Vector3) -Function 528: LoadMaterials() (2 input parameters) +Function 529: LoadMaterials() (2 input parameters) Name: LoadMaterials Return type: Material * Description: Load materials from model file Param[1]: fileName (type: const char *) Param[2]: materialCount (type: int *) -Function 529: LoadMaterialDefault() (0 input parameters) +Function 530: LoadMaterialDefault() (0 input parameters) Name: LoadMaterialDefault Return type: Material Description: Load default material (Supports: DIFFUSE, SPECULAR, NORMAL maps) No input parameters -Function 530: IsMaterialValid() (1 input parameters) +Function 531: IsMaterialValid() (1 input parameters) Name: IsMaterialValid Return type: bool Description: Check if material is valid (shader assigned, map textures loaded in GPU) Param[1]: material (type: Material) -Function 531: UnloadMaterial() (1 input parameters) +Function 532: UnloadMaterial() (1 input parameters) Name: UnloadMaterial Return type: void Description: Unload material from GPU memory (VRAM) Param[1]: material (type: Material) -Function 532: SetMaterialTexture() (3 input parameters) +Function 533: SetMaterialTexture() (3 input parameters) Name: SetMaterialTexture Return type: void Description: Set texture for a material map type (MATERIAL_MAP_DIFFUSE, MATERIAL_MAP_SPECULAR...) Param[1]: material (type: Material *) Param[2]: mapType (type: int) Param[3]: texture (type: Texture2D) -Function 533: SetModelMeshMaterial() (3 input parameters) +Function 534: SetModelMeshMaterial() (3 input parameters) Name: SetModelMeshMaterial Return type: void Description: Set material for a mesh Param[1]: model (type: Model *) Param[2]: meshId (type: int) Param[3]: materialId (type: int) -Function 534: LoadModelAnimations() (2 input parameters) +Function 535: LoadModelAnimations() (2 input parameters) Name: LoadModelAnimations Return type: ModelAnimation * Description: Load model animations from file Param[1]: fileName (type: const char *) Param[2]: animCount (type: int *) -Function 535: UpdateModelAnimation() (3 input parameters) +Function 536: UpdateModelAnimation() (3 input parameters) Name: UpdateModelAnimation Return type: void Description: Update model animation pose (vertex buffers and bone matrices) Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) Param[3]: frame (type: float) -Function 536: UpdateModelAnimationEx() (6 input parameters) +Function 537: UpdateModelAnimationEx() (6 input parameters) Name: UpdateModelAnimationEx Return type: void Description: Update model animation pose, blending two animations @@ -4484,19 +4489,19 @@ Function 536: UpdateModelAnimationEx() (6 input parameters) Param[4]: animB (type: ModelAnimation) Param[5]: frameB (type: float) Param[6]: blend (type: float) -Function 537: UnloadModelAnimations() (2 input parameters) +Function 538: UnloadModelAnimations() (2 input parameters) Name: UnloadModelAnimations Return type: void Description: Unload animation array data Param[1]: animations (type: ModelAnimation *) Param[2]: animCount (type: int) -Function 538: IsModelAnimationValid() (2 input parameters) +Function 539: IsModelAnimationValid() (2 input parameters) Name: IsModelAnimationValid Return type: bool Description: Check model animation skeleton match Param[1]: model (type: Model) Param[2]: anim (type: ModelAnimation) -Function 539: CheckCollisionSpheres() (4 input parameters) +Function 540: CheckCollisionSpheres() (4 input parameters) Name: CheckCollisionSpheres Return type: bool Description: Check collision between two spheres @@ -4504,40 +4509,40 @@ Function 539: CheckCollisionSpheres() (4 input parameters) Param[2]: radius1 (type: float) Param[3]: center2 (type: Vector3) Param[4]: radius2 (type: float) -Function 540: CheckCollisionBoxes() (2 input parameters) +Function 541: CheckCollisionBoxes() (2 input parameters) Name: CheckCollisionBoxes Return type: bool Description: Check collision between two bounding boxes Param[1]: box1 (type: BoundingBox) Param[2]: box2 (type: BoundingBox) -Function 541: CheckCollisionBoxSphere() (3 input parameters) +Function 542: CheckCollisionBoxSphere() (3 input parameters) Name: CheckCollisionBoxSphere Return type: bool Description: Check collision between box and sphere Param[1]: box (type: BoundingBox) Param[2]: center (type: Vector3) Param[3]: radius (type: float) -Function 542: GetRayCollisionSphere() (3 input parameters) +Function 543: GetRayCollisionSphere() (3 input parameters) Name: GetRayCollisionSphere Return type: RayCollision Description: Get collision info between ray and sphere Param[1]: ray (type: Ray) Param[2]: center (type: Vector3) Param[3]: radius (type: float) -Function 543: GetRayCollisionBox() (2 input parameters) +Function 544: GetRayCollisionBox() (2 input parameters) Name: GetRayCollisionBox Return type: RayCollision Description: Get collision info between ray and box Param[1]: ray (type: Ray) Param[2]: box (type: BoundingBox) -Function 544: GetRayCollisionMesh() (3 input parameters) +Function 545: GetRayCollisionMesh() (3 input parameters) Name: GetRayCollisionMesh Return type: RayCollision Description: Get collision info between ray and mesh Param[1]: ray (type: Ray) Param[2]: mesh (type: Mesh) Param[3]: transform (type: Matrix) -Function 545: GetRayCollisionTriangle() (4 input parameters) +Function 546: GetRayCollisionTriangle() (4 input parameters) Name: GetRayCollisionTriangle Return type: RayCollision Description: Get collision info between ray and triangle @@ -4545,7 +4550,7 @@ Function 545: GetRayCollisionTriangle() (4 input parameters) Param[2]: p1 (type: Vector3) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) -Function 546: GetRayCollisionQuad() (5 input parameters) +Function 547: GetRayCollisionQuad() (5 input parameters) Name: GetRayCollisionQuad Return type: RayCollision Description: Get collision info between ray and quad @@ -4554,158 +4559,158 @@ Function 546: GetRayCollisionQuad() (5 input parameters) Param[3]: p2 (type: Vector3) Param[4]: p3 (type: Vector3) Param[5]: p4 (type: Vector3) -Function 547: InitAudioDevice() (0 input parameters) +Function 548: InitAudioDevice() (0 input parameters) Name: InitAudioDevice Return type: void Description: Initialize audio device and context No input parameters -Function 548: CloseAudioDevice() (0 input parameters) +Function 549: CloseAudioDevice() (0 input parameters) Name: CloseAudioDevice Return type: void Description: Close the audio device and context No input parameters -Function 549: IsAudioDeviceReady() (0 input parameters) +Function 550: IsAudioDeviceReady() (0 input parameters) Name: IsAudioDeviceReady Return type: bool Description: Check if audio device has been initialized successfully No input parameters -Function 550: SetMasterVolume() (1 input parameters) +Function 551: SetMasterVolume() (1 input parameters) Name: SetMasterVolume Return type: void Description: Set master volume (listener) Param[1]: volume (type: float) -Function 551: GetMasterVolume() (0 input parameters) +Function 552: GetMasterVolume() (0 input parameters) Name: GetMasterVolume Return type: float Description: Get master volume (listener) No input parameters -Function 552: LoadWave() (1 input parameters) +Function 553: LoadWave() (1 input parameters) Name: LoadWave Return type: Wave Description: Load wave data from file Param[1]: fileName (type: const char *) -Function 553: LoadWaveFromMemory() (3 input parameters) +Function 554: LoadWaveFromMemory() (3 input parameters) Name: LoadWaveFromMemory Return type: Wave Description: Load wave from memory buffer, fileType refers to extension: i.e. '.wav' Param[1]: fileType (type: const char *) Param[2]: fileData (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 554: IsWaveValid() (1 input parameters) +Function 555: IsWaveValid() (1 input parameters) Name: IsWaveValid Return type: bool Description: Check if wave data is valid (data loaded and parameters) Param[1]: wave (type: Wave) -Function 555: LoadSound() (1 input parameters) +Function 556: LoadSound() (1 input parameters) Name: LoadSound Return type: Sound Description: Load sound from file Param[1]: fileName (type: const char *) -Function 556: LoadSoundFromWave() (1 input parameters) +Function 557: LoadSoundFromWave() (1 input parameters) Name: LoadSoundFromWave Return type: Sound Description: Load sound from wave data Param[1]: wave (type: Wave) -Function 557: LoadSoundAlias() (1 input parameters) +Function 558: LoadSoundAlias() (1 input parameters) Name: LoadSoundAlias Return type: Sound Description: Load sound alias, new sound that shares the same sample data as the source sound, does not own the sound data Param[1]: source (type: Sound) -Function 558: IsSoundValid() (1 input parameters) +Function 559: IsSoundValid() (1 input parameters) Name: IsSoundValid Return type: bool Description: Check if sound is valid (data loaded and buffers initialized) Param[1]: sound (type: Sound) -Function 559: UpdateSound() (3 input parameters) +Function 560: UpdateSound() (3 input parameters) Name: UpdateSound Return type: void Description: Update sound buffer with new data (default data format: 32 bit float, stereo) Param[1]: sound (type: Sound) Param[2]: data (type: const void *) Param[3]: frameCount (type: int) -Function 560: UnloadWave() (1 input parameters) +Function 561: UnloadWave() (1 input parameters) Name: UnloadWave Return type: void Description: Unload wave data Param[1]: wave (type: Wave) -Function 561: UnloadSound() (1 input parameters) +Function 562: UnloadSound() (1 input parameters) Name: UnloadSound Return type: void Description: Unload sound Param[1]: sound (type: Sound) -Function 562: UnloadSoundAlias() (1 input parameters) +Function 563: UnloadSoundAlias() (1 input parameters) Name: UnloadSoundAlias Return type: void Description: Unload sound alias (does not deallocate sample data) Param[1]: alias (type: Sound) -Function 563: ExportWave() (2 input parameters) +Function 564: ExportWave() (2 input parameters) Name: ExportWave Return type: bool Description: Export wave data to file, returns true on success Param[1]: wave (type: Wave) Param[2]: fileName (type: const char *) -Function 564: ExportWaveAsCode() (2 input parameters) +Function 565: ExportWaveAsCode() (2 input parameters) Name: ExportWaveAsCode Return type: bool Description: Export wave sample data to code (.h), returns true on success Param[1]: wave (type: Wave) Param[2]: fileName (type: const char *) -Function 565: PlaySound() (1 input parameters) +Function 566: PlaySound() (1 input parameters) Name: PlaySound Return type: void Description: Play a sound Param[1]: sound (type: Sound) -Function 566: StopSound() (1 input parameters) +Function 567: StopSound() (1 input parameters) Name: StopSound Return type: void Description: Stop playing a sound Param[1]: sound (type: Sound) -Function 567: PauseSound() (1 input parameters) +Function 568: PauseSound() (1 input parameters) Name: PauseSound Return type: void Description: Pause a sound Param[1]: sound (type: Sound) -Function 568: ResumeSound() (1 input parameters) +Function 569: ResumeSound() (1 input parameters) Name: ResumeSound Return type: void Description: Resume a paused sound Param[1]: sound (type: Sound) -Function 569: IsSoundPlaying() (1 input parameters) +Function 570: IsSoundPlaying() (1 input parameters) Name: IsSoundPlaying Return type: bool Description: Check if sound is currently playing Param[1]: sound (type: Sound) -Function 570: SetSoundVolume() (2 input parameters) +Function 571: SetSoundVolume() (2 input parameters) Name: SetSoundVolume Return type: void Description: Set volume for a sound (1.0 is max level) Param[1]: sound (type: Sound) Param[2]: volume (type: float) -Function 571: SetSoundPitch() (2 input parameters) +Function 572: SetSoundPitch() (2 input parameters) Name: SetSoundPitch Return type: void Description: Set pitch for a sound (1.0 is base level) Param[1]: sound (type: Sound) Param[2]: pitch (type: float) -Function 572: SetSoundPan() (2 input parameters) +Function 573: SetSoundPan() (2 input parameters) Name: SetSoundPan Return type: void Description: Set pan for a sound (-1.0 left, 0.0 center, 1.0 right) Param[1]: sound (type: Sound) Param[2]: pan (type: float) -Function 573: WaveCopy() (1 input parameters) +Function 574: WaveCopy() (1 input parameters) Name: WaveCopy Return type: Wave Description: Copy a wave to a new wave Param[1]: wave (type: Wave) -Function 574: WaveCrop() (3 input parameters) +Function 575: WaveCrop() (3 input parameters) Name: WaveCrop Return type: void Description: Crop a wave to defined frames range Param[1]: wave (type: Wave *) Param[2]: initFrame (type: int) Param[3]: finalFrame (type: int) -Function 575: WaveFormat() (4 input parameters) +Function 576: WaveFormat() (4 input parameters) Name: WaveFormat Return type: void Description: Convert wave data to desired format @@ -4713,203 +4718,203 @@ Function 575: WaveFormat() (4 input parameters) Param[2]: sampleRate (type: int) Param[3]: sampleSize (type: int) Param[4]: channels (type: int) -Function 576: LoadWaveSamples() (1 input parameters) +Function 577: LoadWaveSamples() (1 input parameters) Name: LoadWaveSamples Return type: float * Description: Load samples data from wave as a 32bit float data array Param[1]: wave (type: Wave) -Function 577: UnloadWaveSamples() (1 input parameters) +Function 578: UnloadWaveSamples() (1 input parameters) Name: UnloadWaveSamples Return type: void Description: Unload samples data loaded with LoadWaveSamples() Param[1]: samples (type: float *) -Function 578: LoadMusicStream() (1 input parameters) +Function 579: LoadMusicStream() (1 input parameters) Name: LoadMusicStream Return type: Music Description: Load music stream from file Param[1]: fileName (type: const char *) -Function 579: LoadMusicStreamFromMemory() (3 input parameters) +Function 580: LoadMusicStreamFromMemory() (3 input parameters) Name: LoadMusicStreamFromMemory Return type: Music Description: Load music stream from data Param[1]: fileType (type: const char *) Param[2]: data (type: const unsigned char *) Param[3]: dataSize (type: int) -Function 580: IsMusicValid() (1 input parameters) +Function 581: IsMusicValid() (1 input parameters) Name: IsMusicValid Return type: bool Description: Check if music stream is valid (context and buffers initialized) Param[1]: music (type: Music) -Function 581: UnloadMusicStream() (1 input parameters) +Function 582: UnloadMusicStream() (1 input parameters) Name: UnloadMusicStream Return type: void Description: Unload music stream Param[1]: music (type: Music) -Function 582: PlayMusicStream() (1 input parameters) +Function 583: PlayMusicStream() (1 input parameters) Name: PlayMusicStream Return type: void Description: Start music playing Param[1]: music (type: Music) -Function 583: IsMusicStreamPlaying() (1 input parameters) +Function 584: IsMusicStreamPlaying() (1 input parameters) Name: IsMusicStreamPlaying Return type: bool Description: Check if music is playing Param[1]: music (type: Music) -Function 584: UpdateMusicStream() (1 input parameters) +Function 585: UpdateMusicStream() (1 input parameters) Name: UpdateMusicStream Return type: void Description: Update buffers for music streaming Param[1]: music (type: Music) -Function 585: StopMusicStream() (1 input parameters) +Function 586: StopMusicStream() (1 input parameters) Name: StopMusicStream Return type: void Description: Stop music playing Param[1]: music (type: Music) -Function 586: PauseMusicStream() (1 input parameters) +Function 587: PauseMusicStream() (1 input parameters) Name: PauseMusicStream Return type: void Description: Pause music playing Param[1]: music (type: Music) -Function 587: ResumeMusicStream() (1 input parameters) +Function 588: ResumeMusicStream() (1 input parameters) Name: ResumeMusicStream Return type: void Description: Resume playing paused music Param[1]: music (type: Music) -Function 588: SeekMusicStream() (2 input parameters) +Function 589: SeekMusicStream() (2 input parameters) Name: SeekMusicStream Return type: void Description: Seek music to a position (in seconds) Param[1]: music (type: Music) Param[2]: position (type: float) -Function 589: SetMusicVolume() (2 input parameters) +Function 590: SetMusicVolume() (2 input parameters) Name: SetMusicVolume Return type: void Description: Set volume for music (1.0 is max level) Param[1]: music (type: Music) Param[2]: volume (type: float) -Function 590: SetMusicPitch() (2 input parameters) +Function 591: SetMusicPitch() (2 input parameters) Name: SetMusicPitch Return type: void Description: Set pitch for music (1.0 is base level) Param[1]: music (type: Music) Param[2]: pitch (type: float) -Function 591: SetMusicPan() (2 input parameters) +Function 592: SetMusicPan() (2 input parameters) Name: SetMusicPan Return type: void Description: Set pan for music (-1.0 left, 0.0 center, 1.0 right) Param[1]: music (type: Music) Param[2]: pan (type: float) -Function 592: GetMusicTimeLength() (1 input parameters) +Function 593: GetMusicTimeLength() (1 input parameters) Name: GetMusicTimeLength Return type: float Description: Get music time length (in seconds) Param[1]: music (type: Music) -Function 593: GetMusicTimePlayed() (1 input parameters) +Function 594: GetMusicTimePlayed() (1 input parameters) Name: GetMusicTimePlayed Return type: float Description: Get current music time played (in seconds) Param[1]: music (type: Music) -Function 594: LoadAudioStream() (3 input parameters) +Function 595: LoadAudioStream() (3 input parameters) Name: LoadAudioStream Return type: AudioStream Description: Load audio stream (to stream raw audio pcm data) Param[1]: sampleRate (type: unsigned int) Param[2]: sampleSize (type: unsigned int) Param[3]: channels (type: unsigned int) -Function 595: IsAudioStreamValid() (1 input parameters) +Function 596: IsAudioStreamValid() (1 input parameters) Name: IsAudioStreamValid Return type: bool Description: Check if an audio stream is valid (buffers initialized) Param[1]: stream (type: AudioStream) -Function 596: UnloadAudioStream() (1 input parameters) +Function 597: UnloadAudioStream() (1 input parameters) Name: UnloadAudioStream Return type: void Description: Unload audio stream and free memory Param[1]: stream (type: AudioStream) -Function 597: UpdateAudioStream() (3 input parameters) +Function 598: UpdateAudioStream() (3 input parameters) Name: UpdateAudioStream Return type: void Description: Update audio stream buffers with data Param[1]: stream (type: AudioStream) Param[2]: data (type: const void *) Param[3]: frameCount (type: int) -Function 598: IsAudioStreamProcessed() (1 input parameters) +Function 599: IsAudioStreamProcessed() (1 input parameters) Name: IsAudioStreamProcessed Return type: bool Description: Check if any audio stream buffers requires refill Param[1]: stream (type: AudioStream) -Function 599: PlayAudioStream() (1 input parameters) +Function 600: PlayAudioStream() (1 input parameters) Name: PlayAudioStream Return type: void Description: Play audio stream Param[1]: stream (type: AudioStream) -Function 600: PauseAudioStream() (1 input parameters) +Function 601: PauseAudioStream() (1 input parameters) Name: PauseAudioStream Return type: void Description: Pause audio stream Param[1]: stream (type: AudioStream) -Function 601: ResumeAudioStream() (1 input parameters) +Function 602: ResumeAudioStream() (1 input parameters) Name: ResumeAudioStream Return type: void Description: Resume audio stream Param[1]: stream (type: AudioStream) -Function 602: IsAudioStreamPlaying() (1 input parameters) +Function 603: IsAudioStreamPlaying() (1 input parameters) Name: IsAudioStreamPlaying Return type: bool Description: Check if audio stream is playing Param[1]: stream (type: AudioStream) -Function 603: StopAudioStream() (1 input parameters) +Function 604: StopAudioStream() (1 input parameters) Name: StopAudioStream Return type: void Description: Stop audio stream Param[1]: stream (type: AudioStream) -Function 604: SetAudioStreamVolume() (2 input parameters) +Function 605: SetAudioStreamVolume() (2 input parameters) Name: SetAudioStreamVolume Return type: void Description: Set volume for audio stream (1.0 is max level) Param[1]: stream (type: AudioStream) Param[2]: volume (type: float) -Function 605: SetAudioStreamPitch() (2 input parameters) +Function 606: SetAudioStreamPitch() (2 input parameters) Name: SetAudioStreamPitch Return type: void Description: Set pitch for audio stream (1.0 is base level) Param[1]: stream (type: AudioStream) Param[2]: pitch (type: float) -Function 606: SetAudioStreamPan() (2 input parameters) +Function 607: SetAudioStreamPan() (2 input parameters) Name: SetAudioStreamPan Return type: void Description: Set pan for audio stream (-1.0 left, 0.0 center, 1.0 right) Param[1]: stream (type: AudioStream) Param[2]: pan (type: float) -Function 607: SetAudioStreamBufferSizeDefault() (1 input parameters) +Function 608: SetAudioStreamBufferSizeDefault() (1 input parameters) Name: SetAudioStreamBufferSizeDefault Return type: void Description: Default size for new audio streams Param[1]: size (type: int) -Function 608: SetAudioStreamCallback() (2 input parameters) +Function 609: SetAudioStreamCallback() (2 input parameters) Name: SetAudioStreamCallback Return type: void Description: Audio thread callback to request new data Param[1]: stream (type: AudioStream) Param[2]: callback (type: AudioCallback) -Function 609: AttachAudioStreamProcessor() (2 input parameters) +Function 610: AttachAudioStreamProcessor() (2 input parameters) Name: AttachAudioStreamProcessor Return type: void Description: Attach audio stream processor to stream, receives frames x 2 samples as 'float' (stereo) Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 610: DetachAudioStreamProcessor() (2 input parameters) +Function 611: DetachAudioStreamProcessor() (2 input parameters) Name: DetachAudioStreamProcessor Return type: void Description: Detach audio stream processor from stream Param[1]: stream (type: AudioStream) Param[2]: processor (type: AudioCallback) -Function 611: AttachAudioMixedProcessor() (1 input parameters) +Function 612: AttachAudioMixedProcessor() (1 input parameters) Name: AttachAudioMixedProcessor Return type: void Description: Attach audio stream processor to the entire audio pipeline, receives frames x 2 samples as 'float' (stereo) Param[1]: processor (type: AudioCallback) -Function 612: DetachAudioMixedProcessor() (1 input parameters) +Function 613: DetachAudioMixedProcessor() (1 input parameters) Name: DetachAudioMixedProcessor Return type: void Description: Detach audio stream processor from the entire audio pipeline diff --git a/tools/rlparser/output/raylib_api.xml b/tools/rlparser/output/raylib_api.xml index 77eb75c73..26066795b 100644 --- a/tools/rlparser/output/raylib_api.xml +++ b/tools/rlparser/output/raylib_api.xml @@ -681,7 +681,7 @@ - + @@ -1099,10 +1099,10 @@ - + - + @@ -1115,10 +1115,13 @@ - + - + + + + @@ -1319,7 +1322,7 @@ - + @@ -2039,7 +2042,7 @@ - + From 6c6a248be837e7286be35969e260a4515278c0b0 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 18 Jul 2026 17:14:03 +0200 Subject: [PATCH 79/94] Update rcore.c --- src/rcore.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rcore.c b/src/rcore.c index ec4d8a473..c1fd31b15 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -2843,7 +2843,7 @@ bool IsPathDirectory(const char *path) } // Check if provided path is an absolute path -static bool IsPathAbsolute(const char *path) +bool IsPathAbsolute(const char *path) { int result = false; From 3094389a2a9002bad8fa4b971dd21b73d8d34c19 Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 18 Jul 2026 17:49:35 +0200 Subject: [PATCH 80/94] Update analyze_codeql.yml --- .github/workflows/analyze_codeql.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/analyze_codeql.yml b/.github/workflows/analyze_codeql.yml index 6598aa063..cd783c8c9 100644 --- a/.github/workflows/analyze_codeql.yml +++ b/.github/workflows/analyze_codeql.yml @@ -71,7 +71,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. @@ -90,7 +90,7 @@ jobs: cmake --build . --config $BUILD_TYPE - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@v4 with: category: "/language:${{matrix.language}}" upload: false @@ -99,7 +99,7 @@ jobs: # Filter out rules with low severity or high false positve rate # Also filter out warnings in third-party code - name: Filter out unwanted errors and warnings - uses: advanced-security/filter-sarif@v1 + uses: advanced-security/filter-sarif@v1.1 with: patterns: | -**:cpp/path-injection @@ -121,7 +121,7 @@ jobs: output: ${{ steps.step1.outputs.sarif-output }}/cpp.sarif - name: Upload CodeQL results to code scanning - uses: github/codeql-action/upload-sarif@v2 + uses: github/codeql-action/upload-sarif@v4 with: sarif_file: ${{ steps.step1.outputs.sarif-output }} category: "/language:${{matrix.language}}" From 9ef6850cc4cee87975883039833aa2486a47413c Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 18 Jul 2026 17:52:07 +0200 Subject: [PATCH 81/94] Update build_examples_windows.yml --- .github/workflows/build_examples_windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_examples_windows.yml b/.github/workflows/build_examples_windows.yml index 186242c24..ccbcaafee 100644 --- a/.github/workflows/build_examples_windows.yml +++ b/.github/workflows/build_examples_windows.yml @@ -25,7 +25,7 @@ jobs: - uses: actions/checkout@master - name: Add MSBuild to PATH - uses: microsoft/setup-msbuild@v1 + uses: microsoft/setup-msbuild@v3 - name: Build Library (MSVC16) run: | From ce40053a6c138f963cf4907289db3893f88cdbe1 Mon Sep 17 00:00:00 2001 From: Ray Date: Mon, 20 Jul 2026 20:36:14 +0200 Subject: [PATCH 82/94] Remove trailing spaces --- src/platforms/rcore_desktop_glfw.c | 8 ++++---- src/platforms/rcore_desktop_rgfw.c | 8 ++++---- src/platforms/rcore_desktop_win32.c | 6 +++--- src/platforms/rcore_drm.c | 2 +- src/rcore.c | 2 +- src/rlgl.h | 10 +++++----- src/rtextures.c | 6 +++--- 7 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/platforms/rcore_desktop_glfw.c b/src/platforms/rcore_desktop_glfw.c index 934815c0f..22bd6b4e2 100644 --- a/src/platforms/rcore_desktop_glfw.c +++ b/src/platforms/rcore_desktop_glfw.c @@ -1198,7 +1198,7 @@ void OpenURL(const char *url) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols"); } else - { + { char *cmd = (char *)RL_CALLOC(strlen(url) + 16, sizeof(char)); #if defined(_WIN32) sprintf(cmd, "explorer \"%s\"", url); @@ -1211,7 +1211,7 @@ void OpenURL(const char *url) #endif // TODO: Replace system() call by custom process int result = system(cmd); - + if (result == -1) TRACELOG(LOG_WARNING, "OpenURL() child process could not be created"); RL_FREE(cmd); } @@ -2186,12 +2186,12 @@ static void MouseScrollCallback(GLFWwindow *window, double xoffset, double yoffs // GLFW3: Cursor ennter callback, when cursor enters the window static void CursorEnterCallback(GLFWwindow *window, int entered) { - if (entered) + if (entered) { // NOTE: Mouse position updated by MouseCursorPosCallback() CORE.Input.Mouse.cursorOnScreen = true; } - else + else { CORE.Input.Mouse.cursorOnScreen = false; CORE.Input.Mouse.currentPosition = (Vector2){ 0 }; diff --git a/src/platforms/rcore_desktop_rgfw.c b/src/platforms/rcore_desktop_rgfw.c index 9907e8a60..9e814f33c 100644 --- a/src/platforms/rcore_desktop_rgfw.c +++ b/src/platforms/rcore_desktop_rgfw.c @@ -1488,7 +1488,7 @@ void OpenURL(const char *url) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols"); } else - { + { char *cmd = (char *)RL_CALLOC(strlen(url) + 16, sizeof(char)); #if defined(_WIN32) sprintf(cmd, "explorer \"%s\"", url); @@ -1621,7 +1621,7 @@ void PollInputEvents(void) while (mg_gamepads_check_event(&platform.minigamepad, &gamepad_event)) { int gamepadIndex = gamepad_event.gamepad->index; - + switch (gamepad_event.type) { case MG_EVENT_BUTTON_PRESS: @@ -1682,10 +1682,10 @@ void PollInputEvents(void) if (platform.minigamepad.gamepads[gamepadIndex].axes[i].supported) axisCount += 1; else break; } - + CORE.Input.Gamepad.axisCount[gamepadIndex] = axisCount; snprintf(CORE.Input.Gamepad.name[gamepadIndex], MAX_GAMEPAD_NAME_LENGTH, "%s", platform.minigamepad.gamepads[gamepadIndex].name); - + } break; case MG_EVENT_GAMEPAD_DISCONNECT: CORE.Input.Gamepad.ready[gamepadIndex] = false; break; default: break; diff --git a/src/platforms/rcore_desktop_win32.c b/src/platforms/rcore_desktop_win32.c index a6e85a657..1e560aa56 100644 --- a/src/platforms/rcore_desktop_win32.c +++ b/src/platforms/rcore_desktop_win32.c @@ -1264,11 +1264,11 @@ void OpenURL(const char *url) TRACELOG(LOG_WARNING, "SYSTEM: Provided URL must start with 'http://' or 'https://' protocols"); } else - { + { int len = strlen(url) + 16; char *cmd = (char *)RL_CALLOC(len, sizeof(char)); snprintf(cmd, len, "explorer \"%s\"", url); - + int result = system(cmd); if (result == -1) TRACELOG(LOG_WARNING, "OpenURL() child process could not be created"); RL_FREE(cmd); @@ -1299,7 +1299,7 @@ void SetMousePosition(int x, int y) if (!CORE.Input.Mouse.cursorLocked) { CORE.Input.Mouse.currentPosition = (Vector2){ (float)x, (float)y }; - + TRACELOG(LOG_WARNING, "SetMousePosition not implemented at platform level"); } else TRACELOG(LOG_WARNING, "INPUT: MOUSE: Cursor not enabled"); diff --git a/src/platforms/rcore_drm.c b/src/platforms/rcore_drm.c index 4d4a4d3bf..fce19408b 100644 --- a/src/platforms/rcore_drm.c +++ b/src/platforms/rcore_drm.c @@ -1444,7 +1444,7 @@ int InitPlatform(void) return -1; } - // WARNING: Providing framebufferAttribs is not logically necessary, + // WARNING: Providing framebufferAttribs is not logically necessary, // but it may prevent segfaults on some nvidia drivers if (!eglChooseConfig(platform.device, framebufferAttribs, NULL, 0, &numConfigs)) { diff --git a/src/rcore.c b/src/rcore.c index c1fd31b15..450a4cec5 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -2846,7 +2846,7 @@ bool IsPathDirectory(const char *path) bool IsPathAbsolute(const char *path) { int result = false; - + if ((path != NULL) && (path[0] != '\0')) { #if defined(_WIN32) diff --git a/src/rlgl.h b/src/rlgl.h index 7f3fe54cd..be24bbb78 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -3793,7 +3793,7 @@ unsigned char *rlReadScreenPixels(int width, int height) { unsigned char *imgData = (unsigned char *)RL_CALLOC(width*height*4, sizeof(unsigned char)); - // NOTE: Buffer retrieved is GL_FRONT in single-buffered configurations + // NOTE: Buffer retrieved is GL_FRONT in single-buffered configurations // and GL_BACK in double-buffered configurations, make sure to call it at the end of frame //glReadBuffer(GL_BACK); @@ -5243,7 +5243,7 @@ static int rlGetPixelDataSize(int width, int height, int format) int blockHeight = (height + 3)/4; unsigned long long dataSizeBytes = (unsigned long long)blockWidth*blockHeight*8; if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes; - + } break; case RL_PIXELFORMAT_COMPRESSED_DXT3_RGBA: case RL_PIXELFORMAT_COMPRESSED_DXT5_RGBA: @@ -5254,7 +5254,7 @@ static int rlGetPixelDataSize(int width, int height, int format) int blockHeight = (height + 3)/4; unsigned long long dataSizeBytes = (unsigned long long)blockWidth*blockHeight*16; if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes; - + } break; case RL_PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: // 4 bytes per each 4x4 block { @@ -5262,7 +5262,7 @@ static int rlGetPixelDataSize(int width, int height, int format) int blockHeight = (height + 3)/4; unsigned long long dataSizeBytes = (unsigned long long)blockWidth*blockHeight*4; if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes; - + } break; default: break; } @@ -5274,7 +5274,7 @@ static int rlGetPixelDataSize(int width, int height, int format) unsigned long long dataSizeBytes = ((unsigned long long)width*height*bpp) >> 3; // Get size in bytes (dividing by 8) if (dataSizeBytes < INT_MAX) dataSize = (int)dataSizeBytes; } - + if (dataSize == 0) TRACELOG(LOG_WARNING, "Requested image size is larger than 2GB, it can not be allocated"); return dataSize; diff --git a/src/rtextures.c b/src/rtextures.c index 15f009354..9f0fa7645 100644 --- a/src/rtextures.c +++ b/src/rtextures.c @@ -1250,7 +1250,7 @@ Image ImageFromImage(Image image, Rectangle rec) for (int y = 0; y < (int)rec.height; y++) { - memcpy(((unsigned char *)result.data) + y*(int)rec.width*bytesPerPixel, + memcpy(((unsigned char *)result.data) + y*(int)rec.width*bytesPerPixel, ((unsigned char *)image.data) + ((y + (int)rec.y)*image.width + (int)rec.x)*bytesPerPixel, (int)rec.width*bytesPerPixel); } @@ -5523,7 +5523,7 @@ int GetPixelDataSize(int width, int height, int format) case PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA: bpp = 2; break; default: break; } - + unsigned long long dataSizeBytes = ((unsigned long long)width*height*bpp) >> 3; // Get size in bytes (dividing by 8) if (dataSizeBytes < INT_MAX) @@ -5538,7 +5538,7 @@ int GetPixelDataSize(int width, int height, int format) else if ((format >= PIXELFORMAT_COMPRESSED_DXT3_RGBA) && (format < PIXELFORMAT_COMPRESSED_ASTC_8x8_RGBA)) dataSize = 16; } } - + // NOTE: In case required image data larger than 2GB, no memory allocated at all (NULL) if (dataSize == 0) TRACELOG(LOG_WARNING, "Requested image size is larger than 2GB, it can not be allocated"); From 1c3a7748ea665a35b881f991783a998e385a0e33 Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 21 Jul 2026 08:40:56 +0200 Subject: [PATCH 83/94] Update examples dep. raygui 5.0 --- examples/audio/raygui.h | 2299 +++++++------ examples/core/raygui.h | 2299 +++++++------ examples/models/raygui.h | 2301 +++++++------ examples/shaders/raygui.h | 2299 +++++++------ examples/shapes/raygui.h | 2301 +++++++------ examples/text/raygui.h | 6460 ++++++++++++++++++++++++++++++++++++ examples/textures/raygui.h | 6460 ++++++++++++++++++++++++++++++++++++ 7 files changed, 19690 insertions(+), 4729 deletions(-) create mode 100644 examples/text/raygui.h create mode 100644 examples/textures/raygui.h diff --git a/examples/audio/raygui.h b/examples/audio/raygui.h index 03e487912..f7a116150 100644 --- a/examples/audio/raygui.h +++ b/examples/audio/raygui.h @@ -1,6 +1,6 @@ /******************************************************************************************* * -* raygui v5.0-dev - A simple and easy-to-use immediate-mode gui library +* raygui v5.0 - A simple and easy-to-use immediate-mode gui library * * DESCRIPTION: * raygui is a tools-dev-focused immediate-mode-gui library based on raylib but also @@ -37,7 +37,7 @@ * - Line * - Panel --> StatusBar * - ScrollPanel --> StatusBar -* - TabBar --> Button +* - TabBar --> Toggle, Button * * # Basic Controls * - Label @@ -134,6 +134,10 @@ * Includes custom ricons.h header defining a set of custom icons, * this file can be generated using rGuiIcons tool * +* #define RAYGUI_FONT_ICONS_BAKING +* On gui font loading from style file, append the icons to font atlas image, so, +* icons can be drawn along the text as a texture, instead of using shapes to draw them +* * #define RAYGUI_DEBUG_RECS_BOUNDS * Draw control bounds rectangles for debug * @@ -141,16 +145,26 @@ * Draw text bounds rectangles for debug * * VERSIONS HISTORY: -* 5.0 (xx-Mar-2026) ADDED: Support up to 32 controls (v500) +* 5.0 (20-Jul-2026) ADDED: NEW control: GuiTabBar() +* ADDED: Support up to 512 icons (v500) +* ADDED: Support icons baking into font atlas image * ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes -* ADDED: GuiValueBoxFloat() +* ADDED: GuiValueBoxFloat(), with floats support * ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP * ADDED: GuiListView() property: LIST_ITEMS_BORDER_WIDTH -* ADDED: GuiLoadIconsFromMemory() -* ADDED: Multiple new icons +* ADDED: GuiLoadIconsFromMemory(), used by GuiLoadIcons() * ADDED: Macros for inputs customization, raylib decoupling +* ADDED: Control result return values: 1-RESULT_PRESSED, 2-RESULT_CHANGED, >2-Control_custom * REMOVED: GuiSpinner() from controls list, using BUTTON + VALUEBOX properties * REMOVED: GuiSliderPro(), functionality was redundant +* REMOVED: TextSplit() raylib function requirement on RAYGUI_STANDALONE +* REDESIGNED: WARNING: GuiLoadStyleFromMemory() to support icons baking into font atlas +* REDESIGNED: GuiToggleGroup() to process rows/cols with no need for GuiTextSplit() +* REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion +* REDESIGNED: WARNING: TEXT_LINE_SPACING does not consider text height, only lines spacing +* REDESIGNED: WARNING: GuiMessageBox(), added parameter for btn return, unify result +* REDESIGNED: WARNING: GuiTextInputBox(), added parameter for btn return, unify result +* REVIEWED: GuiLoadIconsFromMemory(), fixed memory issues * REVIEWED: Controls using text labels to use LABEL properties * REVIEWED: Replaced sprintf() by snprintf() for more safety * REVIEWED: GuiTabBar(), close tab with mouse middle button @@ -165,8 +179,6 @@ * REVIEWED: GuiProgressBar(), improved borders computing * REVIEWED: GuiTextBox(), multiple improvements: autocursor and more * REVIEWED: Functions descriptions, removed wrong return value reference -* REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion -* REDESIGNED: WARNING: TEXT_LINE_SPACING does not consider text height, only lines spacing * * 4.0 (12-Sep-2023) ADDED: GuiToggleSlider() * ADDED: GuiColorPickerHSV() and GuiColorPanelHSV() @@ -273,7 +285,7 @@ * 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria * * DEPENDENCIES: -* raylib 5.6-dev - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing +* raylib 6.1-dev - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing * * STANDALONE MODE: * By default raygui depends on raylib mostly for the inputs and the drawing functionality but that dependency can be disabled @@ -340,10 +352,10 @@ #ifndef RAYGUI_H #define RAYGUI_H -#define RAYGUI_VERSION_MAJOR 4 -#define RAYGUI_VERSION_MINOR 5 +#define RAYGUI_VERSION_MAJOR 5 +#define RAYGUI_VERSION_MINOR 0 #define RAYGUI_VERSION_PATCH 0 -#define RAYGUI_VERSION "5.0-dev" +#define RAYGUI_VERSION "5.0" #if !defined(RAYGUI_STANDALONE) #include "raylib.h" @@ -357,7 +369,13 @@ #elif defined(USE_LIBTYPE_SHARED) #define RAYGUIAPI __declspec(dllimport) // Using the library as a Win32 shared library (.dll) #endif - #define _CRT_SECURE_NO_WARNINGS // Disable unsafe warnings on scanf() functions in MSVC + #if !defined(_CRT_SECURE_NO_WARNINGS) + #define _CRT_SECURE_NO_WARNINGS // Disable unsafe warnings on scanf() functions in MSVC + #endif +#else + #if defined(BUILD_LIBTYPE_SHARED) + #define RAYGUIAPI __attribute__((visibility("default"))) // Building as a Unix shared library (.so/.dylib) + #endif #endif // Function specifiers definition @@ -377,8 +395,8 @@ #define RAYGUI_LOG(...) #endif +#if !defined(RAYGUI_STANDALONE) // Macros to define required UI inputs, including mapping to gamepad controls -// TODO: Define additionally required macros for missing inputs #if !defined(GUI_BUTTON_DOWN) #define GUI_BUTTON_DOWN (IsMouseButtonDown(MOUSE_LEFT_BUTTON) || IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) #endif @@ -389,13 +407,15 @@ #if !defined(GUI_BUTTON_PRESSED) #define GUI_BUTTON_PRESSED (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsGamepadButtonPressed(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) #endif -// TODO: WARNING: GuiTabBar() still requires IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON) +#if !defined(GUI_BUTTON_PRESSED_MID) + #define GUI_BUTTON_PRESSED_MID (IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON) || IsGamepadButtonPressed(0, GAMEPAD_BUTTON_RIGHT_FACE_UP)) +#endif #if !defined(GUI_BUTTON_RELEASED) #define GUI_BUTTON_RELEASED (IsMouseButtonReleased(MOUSE_LEFT_BUTTON) || IsGamepadButtonReleased(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) #endif #if !defined(GUI_SCROLL_DELTA) // Mapping to scroll delta changes - // TODO: Review inconsistencies between platforms + // TODO: Review mouse scroll inconsistencies between platforms #if defined(PLATFORM_WEB) // NOTE: Gamepad axis triggers not detected on web platform #define GUI_SCROLL_DELTA ((float)IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_TRIGGER_2) - (float)IsGamepadButtonDown(0, GAMEPAD_BUTTON_LEFT_TRIGGER_2)) @@ -415,6 +435,18 @@ #if !defined(GUI_INPUT_KEY) #define GUI_INPUT_KEY GetCharPressed() #endif +#else + #define GUI_BUTTON_DOWN 0 + #define GUI_BUTTON_DOWN_ALT 0 + #define GUI_BUTTON_PRESSED 0 + #define GUI_BUTTON_PRESSED_MID 0 + #define GUI_BUTTON_RELEASED 0 + #define GUI_SCROLL_DELTA 0 + #define GUI_POINTER_POSITION (Vector2){ 0 } + #define GUI_KEY_DOWN(key) 0 + #define GUI_KEY_PRESSED(key) 0 + #define GUI_INPUT_KEY 0 +#endif //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -449,6 +481,8 @@ unsigned char a; } Color; +#define BLANK (Color){ 0, 0, 0, 0 } // Blank (Transparent) + // Rectangle type typedef struct Rectangle { float x; @@ -457,7 +491,7 @@ float height; } Rectangle; - // TODO: Texture2D type is very coupled to raylib, required by Font type + // NOTE: Texture2D type is very coupled to raylib, required by Font type // It should be redesigned to be provided by user typedef struct Texture { unsigned int id; // OpenGL texture id @@ -488,7 +522,7 @@ Image image; // Character image data } GlyphInfo; - // TODO: Font type is very coupled to raylib, mostly required by GuiLoadStyle() + // NOTE: Font type is very coupled to raylib, mostly required by GuiLoadStyle() // It should be redesigned to be provided by user typedef struct Font { int baseSize; // Base size (default chars height) @@ -521,6 +555,15 @@ typedef struct GuiTextStyle { } GuiTextStyle; */ +// Gui control result +typedef enum { + RESULT_NONE = 0, + RESULT_PRESSED = 1, + RESULT_CHANGED = 2, + + RESULT_TAB_CLOSE = 4 // GuiTabBar(), tab close request +} GuiResult; + // Gui control state typedef enum { STATE_NORMAL = 0, @@ -553,88 +596,95 @@ typedef enum { } GuiTextWrapMode; // Gui controls +// NOTE: Up to 16 controls supported or 32 controls (v500) typedef enum { // Default -> populates to all controls when set - DEFAULT = 0, + DEFAULT = 0, // Basic controls - LABEL, // Used also for: LABELBUTTON - BUTTON, - TOGGLE, // Used also for: TOGGLEGROUP - SLIDER, // Used also for: SLIDERBAR, TOGGLESLIDER - PROGRESSBAR, - CHECKBOX, - COMBOBOX, - DROPDOWNBOX, - TEXTBOX, // Used also for: TEXTBOXMULTI - VALUEBOX, - CONTROL11, - LISTVIEW, - COLORPICKER, - SCROLLBAR, - STATUSBAR + LABEL = 1, // Used also for: LABELBUTTON + BUTTON = 2, + TOGGLE = 3, // Used also for: TOGGLEGROUP + SLIDER = 4, // Used also for: SLIDERBAR, TOGGLESLIDER + PROGRESSBAR = 5, + CHECKBOX = 6, + COMBOBOX = 7, + DROPDOWNBOX = 8, + TEXTBOX = 9, // Used also for: TEXTBOXMULTI + VALUEBOX = 10, + TABBAR = 11, + LISTVIEW = 12, + COLORPICKER = 13, + SCROLLBAR = 14, + STATUSBAR = 15 + // NOTE: More controls can be added if required } GuiControl; -// Gui base properties for every control -// NOTE: RAYGUI_MAX_PROPS_BASE properties (by default 16 properties) +// Controls BASE properties for every control (RAYGUI_MAX_PROPS_BASE = 16) +// NOTE: Properties required for all controls, DEFAULT control sets +// default values for them but they can be overriden per control typedef enum { - BORDER_COLOR_NORMAL = 0, // Control border color in STATE_NORMAL - BASE_COLOR_NORMAL, // Control base color in STATE_NORMAL - TEXT_COLOR_NORMAL, // Control text color in STATE_NORMAL - BORDER_COLOR_FOCUSED, // Control border color in STATE_FOCUSED - BASE_COLOR_FOCUSED, // Control base color in STATE_FOCUSED - TEXT_COLOR_FOCUSED, // Control text color in STATE_FOCUSED - BORDER_COLOR_PRESSED, // Control border color in STATE_PRESSED - BASE_COLOR_PRESSED, // Control base color in STATE_PRESSED - TEXT_COLOR_PRESSED, // Control text color in STATE_PRESSED - BORDER_COLOR_DISABLED, // Control border color in STATE_DISABLED - BASE_COLOR_DISABLED, // Control base color in STATE_DISABLED - TEXT_COLOR_DISABLED, // Control text color in STATE_DISABLED - BORDER_WIDTH = 12, // Control border size, 0 for no border - //TEXT_SIZE, // Control text size (glyphs max height) -> GLOBAL for all controls - //TEXT_SPACING, // Control text spacing between glyphs -> GLOBAL for all controls - //TEXT_LINE_SPACING, // Control text spacing between lines -> GLOBAL for all controls - TEXT_PADDING = 13, // Control text padding, not considering border - TEXT_ALIGNMENT = 14, // Control text horizontal alignment inside control text bound (after border and padding) - //TEXT_WRAP_MODE // Control text wrap-mode inside text bounds -> GLOBAL for all controls + BORDER_COLOR_NORMAL = 0, // Control border color in STATE_NORMAL + BASE_COLOR_NORMAL = 1, // Control base color in STATE_NORMAL + TEXT_COLOR_NORMAL = 2, // Control text color in STATE_NORMAL + BORDER_COLOR_FOCUSED = 3, // Control border color in STATE_FOCUSED + BASE_COLOR_FOCUSED = 4, // Control base color in STATE_FOCUSED + TEXT_COLOR_FOCUSED = 5, // Control text color in STATE_FOCUSED + BORDER_COLOR_PRESSED = 6, // Control border color in STATE_PRESSED + BASE_COLOR_PRESSED = 7, // Control base color in STATE_PRESSED + TEXT_COLOR_PRESSED = 8, // Control text color in STATE_PRESSED + BORDER_COLOR_DISABLED = 9, // Control border color in STATE_DISABLED + BASE_COLOR_DISABLED = 10, // Control base color in STATE_DISABLED + TEXT_COLOR_DISABLED = 11, // Control text color in STATE_DISABLED + BORDER_WIDTH = 12, // Control border size, 0 for no border + TEXT_PADDING = 13, // Control text padding, not considering border + TEXT_ALIGNMENT = 14, // Control text horizontal alignment inside control text bound (after border and padding): 0-Left, 1-Center, 2-Right + BASEPROP16 = 15 // Not used yet... } GuiControlProperty; -// TODO: Which text styling properties should be global or per-control? -// At this moment TEXT_PADDING and TEXT_ALIGNMENT is configured and saved per control while -// TEXT_SIZE, TEXT_SPACING, TEXT_LINE_SPACING, TEXT_ALIGNMENT_VERTICAL, TEXT_WRAP_MODE are global and -// should be configured by user as needed while defining the UI layout -// Gui extended properties depend on control -// NOTE: RAYGUI_MAX_PROPS_EXTENDED properties (by default, max 8 properties) +// WARNING: Some properties have been chosen to be global with DEFAULT - EXTENDED properties: +// - TEXT_SIZE, // Control text size (glyphs max height) +// - TEXT_SPACING, // Control text spacing between glyphs +// - TEXT_LINE_SPACING, // Control text spacing between lines +// - TEXT_WRAP_MODE // Control text wrap-mode inside text bounds +// +// While other properties can be setup per globally (DEFAULT) or per control: +// - TEXT_PADDING // Control text padding, not considering border +// - TEXT_ALIGNMENT // Control text horizontal alignment inside control text bound + + +// Controls EXTENDED properties (RAYGUI_MAX_PROPS_EXTENDED = 8) +// WARNING: Only 8 slots vailable for those properties per control, including DEFAULT //---------------------------------------------------------------------------------- -// DEFAULT extended properties -// NOTE: Those properties are common to all controls or global -// WARNING: Only 8 slots vailable for those properties by default +// DEFAULT control, extended properties +// NOTE: Those properties are global for all controls, they can not be setup per control typedef enum { - TEXT_SIZE = 16, // Text size (glyphs max height) - TEXT_SPACING, // Text spacing between glyphs - LINE_COLOR, // Line control color - BACKGROUND_COLOR, // Background color - TEXT_LINE_SPACING, // Text spacing between lines - TEXT_ALIGNMENT_VERTICAL, // Text vertical alignment inside text bounds (after border and padding) - TEXT_WRAP_MODE // Text wrap-mode inside text bounds - //TEXT_DECORATION // Text decoration: 0-None, 1-Underline, 2-Line-through, 3-Overline - //TEXT_DECORATION_THICK // Text decoration line thickness + TEXT_SIZE = 16, // Text size (glyphs max height) + TEXT_SPACING = 17, // Text spacing between glyphs + LINE_COLOR = 18, // Line control color + BACKGROUND_COLOR = 19, // Background color + TEXT_LINE_SPACING = 20, // Text spacing between lines + TEXT_ALIGNMENT_VERTICAL = 21, // Text vertical alignment inside text bounds (after border and padding): 0-Top, 1-Middle, 2-Bottom + TEXT_WRAP_MODE = 22, // Text wrap-mode inside text bounds + EXTPROP08 = 23 // Not used yet... } GuiDefaultProperty; -// Other possible text properties: -// TEXT_WEIGHT // Normal, Italic, Bold -> Requires specific font change -// TEXT_INDENT // Text indentation -> Now using TEXT_PADDING... +// Other possible text extended properties: +// TEXT_DECORATION // Text decoration: 0-None, 1-Underline, 2-Line-through, 3-Overline +// TEXT_DECORATION_THICK // Text decoration line thickness +// TEXT_FONT_WEIGHT // Text font weight: 0-Normal, 1-Bold, 2-Italic -> Requires specific font change // Label //typedef enum { } GuiLabelProperty; -// Button/Spinner +// Button //typedef enum { } GuiButtonProperty; // Toggle/ToggleGroup typedef enum { GROUP_PADDING = 16, // ToggleGroup separation between toggles + GROUP_WIDTH_FULL // ToggleGroup bounds width considers all items: 0-Width per item, 1-Full width } GuiToggleProperty; // Slider/SliderBar @@ -646,7 +696,7 @@ typedef enum { // ProgressBar typedef enum { PROGRESS_PADDING = 16, // ProgressBar internal padding - PROGRESS_SIDE, // ProgressBar increment side: 0-left->right, 1-right-left + PROGRESS_SIDE, // ProgressBar increment side: 0-Left->Right, 1-Right->Left } GuiProgressBarProperty; // ScrollBar @@ -675,12 +725,12 @@ typedef enum { ARROW_PADDING = 16, // DropdownBox arrow separation from border and items DROPDOWN_ITEMS_SPACING, // DropdownBox items separation DROPDOWN_ARROW_HIDDEN, // DropdownBox arrow hidden - DROPDOWN_ROLL_UP // DropdownBox roll up flag (default rolls down) + DROPDOWN_ROLL_UP // DropdownBox roll up flag: 0-Roll down, 1-Roll up } GuiDropdownBoxProperty; // TextBox/TextBoxMulti/ValueBox/Spinner typedef enum { - TEXT_READONLY = 16, // TextBox in read-only mode: 0-text editable, 1-text no-editable + TEXT_READONLY = 16, // TextBox in read-only mode: 0-Text editable, 1-Text read-only } GuiTextBoxProperty; // ValueBox/Spinner @@ -689,31 +739,35 @@ typedef enum { SPINNER_BUTTON_SPACING, // Spinner buttons separation } GuiValueBoxProperty; -// Control11 -//typedef enum { } GuiControl11Property; +// TabBar +typedef enum { + TAB_ITEMS_WIDTH = 16, // TabBar tab items width + TAB_CLOSE_BUTTON, // TabBar tab close button: 0-Not shown, 1-Shown + TAB_LINE_SIDE, // TabBar tabs side: 0-Bottom, 1-Top +} GuiTabBarProperty; // ListView +#define SCROLLBAR_LEFT_SIDE 0 +#define SCROLLBAR_RIGHT_SIDE 1 + typedef enum { LIST_ITEMS_HEIGHT = 16, // ListView items height LIST_ITEMS_SPACING, // ListView items separation SCROLLBAR_WIDTH, // ListView scrollbar size (usually width) - SCROLLBAR_SIDE, // ListView scrollbar side (0-SCROLLBAR_LEFT_SIDE, 1-SCROLLBAR_RIGHT_SIDE) + SCROLLBAR_SIDE, // ListView scrollbar side: 0-Left side, 1-Right Side LIST_ITEMS_BORDER_NORMAL, // ListView items border enabled in normal state LIST_ITEMS_BORDER_WIDTH // ListView items border width } GuiListViewProperty; // ColorPicker typedef enum { - COLOR_SELECTOR_SIZE = 16, + COLOR_SELECTOR_SIZE = 16, // ColorPicker selector square size HUEBAR_WIDTH, // ColorPicker right hue bar width HUEBAR_PADDING, // ColorPicker right hue bar separation from panel HUEBAR_SELECTOR_HEIGHT, // ColorPicker right hue bar selector height HUEBAR_SELECTOR_OVERFLOW // ColorPicker right hue bar selector overflow } GuiColorPickerProperty; -#define SCROLLBAR_LEFT_SIDE 0 -#define SCROLLBAR_RIGHT_SIDE 1 - //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- @@ -747,6 +801,7 @@ RAYGUIAPI int GuiGetStyle(int control, int property); // Get one style // Styles loading functions RAYGUIAPI void GuiLoadStyle(const char *fileName); // Load style file over global style variable (.rgs) +RAYGUIAPI void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only) RAYGUIAPI void GuiLoadStyleDefault(void); // Load style default over global style // Tooltips management functions @@ -760,6 +815,7 @@ RAYGUIAPI const char *GuiIconText(int iconId, const char *text); // Get text wit RAYGUIAPI void GuiSetIconScale(int scale); // Set default icon drawing size RAYGUIAPI unsigned int *GuiGetIcons(void); // Get raygui icons data pointer RAYGUIAPI char **GuiLoadIcons(const char *fileName, bool loadIconsName); // Load raygui icons file (.rgi) into internal icons data +RAYGUIAPI char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName); // Load raygui icons file (.rgi) from memory into internal icons data RAYGUIAPI void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color); // Draw icon using pixel size at specified position #endif @@ -773,7 +829,6 @@ RAYGUIAPI int GuiWindowBox(Rectangle bounds, const char *title); RAYGUIAPI int GuiGroupBox(Rectangle bounds, const char *text); // Group Box control with text name RAYGUIAPI int GuiLine(Rectangle bounds, const char *text); // Line separator control, could contain text RAYGUIAPI int GuiPanel(Rectangle bounds, const char *text); // Panel control, useful to group controls -RAYGUIAPI int GuiTabBar(Rectangle bounds, char **text, int count, int *active); // Tab Bar control, returns TAB to be closed or -1 RAYGUIAPI int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view); // Scroll Panel control // Basic controls set @@ -801,15 +856,17 @@ RAYGUIAPI int GuiGrid(Rectangle bounds, const char *text, float spacing, int sub // Advance controls set RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active); // List View control -RAYGUIAPI int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus); // List View with extended parameters -RAYGUIAPI int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons); // Message Box control, displays a message -RAYGUIAPI int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive); // Text Input Box control, ask for text, supports secret -RAYGUIAPI int GuiColorPicker(Rectangle bounds, const char *text, Color *color); // Color Picker control (multiple color controls) +RAYGUIAPI int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus); // List View control, using text entries list and returning focus entry +RAYGUIAPI int GuiTabBar(Rectangle bounds, const char *text, int *hscroll, int *active); // Tab Bar control +RAYGUIAPI int GuiTabBarEx(Rectangle bounds, char **text, int count, int *hscroll, int *active, int *focus); // Tab Bar control, using text entries list and returning focus entry +RAYGUIAPI int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *btnText, int *btnActive); // Message Box control, displays a message +RAYGUIAPI int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, char *text, int textSize, const char *btnText, int *btnActive, bool *secretViewActive); // Text Input Box control, ask for text, supports secret +RAYGUIAPI int GuiColorPicker(Rectangle bounds, const char *text, Color *color); // Color Picker control, includes Color bar controls RAYGUIAPI int GuiColorPanel(Rectangle bounds, const char *text, Color *color); // Color Panel control RAYGUIAPI int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha); // Color Bar Alpha control RAYGUIAPI int GuiColorBarHue(Rectangle bounds, const char *text, float *value); // Color Bar Hue control -RAYGUIAPI int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Picker control that avoids conversion to RGB on each call (multiple color controls) -RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control that updates Hue-Saturation-Value color value, used by GuiColorPickerHSV() +RAYGUIAPI int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Picker control, using Hue-Saturation-Value color data, includes Color bar controls +RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control, using Hue-Saturation-Value color data //---------------------------------------------------------------------------------------------------------- #if !defined(RAYGUI_NO_ICONS) @@ -1069,16 +1126,17 @@ typedef enum { ICON_CONE = 247, ICON_ELLIPSOID = 248, ICON_CAPSULE = 249, - ICON_250 = 250, - ICON_251 = 251, - ICON_252 = 252, - ICON_253 = 253, - ICON_254 = 254, - ICON_255 = 255 + ICON_FILETYPE_FONT = 250, + ICON_FILETYPE_3D = 251, + ICON_FILETYPE_CODE_XML = 252, + ICON_FILETYPE_CODE_C = 253, + ICON_FILETYPE_CODE_PYTHON = 254, + ICON_FILETYPE_CODE_JS = 255, + ICON_FILETYPE_ICON = 256, } GuiIconName; #endif -#endif +#endif // RAYGUI_NO_ICONS #if defined(__cplusplus) } // Prevents name mangling of functions @@ -1094,11 +1152,11 @@ typedef enum { #if defined(RAYGUI_IMPLEMENTATION) -#include // required for: isspace() [GuiTextBox()] #include // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()] #include // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy() #include // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()] #include // Required for: roundf() [GuiColorPicker()] +#include // Required for: isspace() [GuiTextBox()] // Allow custom memory allocators #if defined(RAYGUI_MALLOC) || defined(RAYGUI_CALLOC) || defined(RAYGUI_FREE) @@ -1127,9 +1185,11 @@ typedef enum { #if !defined(RAYGUI_NO_ICONS) && !defined(RAYGUI_CUSTOM_ICONS) // Embedded icons, no external file provided -#define RAYGUI_ICON_SIZE 16 // Size of icons in pixels (squared) -#define RAYGUI_ICON_MAX_ICONS 256 // Maximum number of icons -#define RAYGUI_ICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id +#define RAYGUI_ICON_SIZE 16 // Size of icons in pixels (squared) +#define RAYGUI_ICON_MAX_ICONS 512 // Maximum number of icons +#define RAYGUI_ICON_MAX_FONT_BACKED 257 // Maximum number of icons to back in font atlas +#define RAYGUI_ICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id +#define RAYGUI_ICON_FONT_ATLAS_PADDING 1 // Padding between backed icons in font atlas // Icons data is defined by bit array (every bit represents one pixel) // Those arrays are stored as unsigned int data arrays, so, @@ -1147,7 +1207,7 @@ typedef enum { // NOTE 2: A different icon set could be loaded over this array using GuiLoadIcons(), // but loaded icons set must be same RAYGUI_ICON_SIZE and no more than RAYGUI_ICON_MAX_ICONS // -// guiIcons size is by default: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 KB +// guiIcons size is by default: 512*(16*16/32) = 16384 bytes = 16 KB //---------------------------------------------------------------------------------- static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_NONE @@ -1400,18 +1460,20 @@ static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = 0x00800000, 0x01400140, 0x02200220, 0x04100410, 0x08080808, 0x1c1c13e4, 0x08081004, 0x000007f0, // ICON_CONE 0x00000000, 0x07e00000, 0x20841918, 0x40824082, 0x40824082, 0x19182084, 0x000007e0, 0x00000000, // ICON_ELLIPSOID 0x00000000, 0x00000000, 0x20041ff8, 0x40024002, 0x40024002, 0x1ff82004, 0x00000000, 0x00000000, // ICON_CAPSULE - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_250 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_251 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_252 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_253 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_254 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_255 + 0x3ff00000, 0x201c2010, 0x21042004, 0x22842384, 0x264426c4, 0x2c242fe4, 0x20043e74, 0x00003ffc, // ICON_FILETYPE_FONT + 0x3ff00000, 0x201c2010, 0x20042004, 0x27742004, 0x29742944, 0x27742944, 0x20042004, 0x00003ffc, // ICON_FILETYPE_3D + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x24242244, 0x24242814, 0x20042244, 0x00003ffc, // ICON_FILETYPE_XML + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x21042f04, 0x21042104, 0x20042f04, 0x00003ffc, // ICON_FILETYPE_C + 0x3ff00000, 0x201c2010, 0x23842004, 0x2bf42a04, 0x2fd42814, 0x21c42054, 0x20042004, 0x00003ffc, // ICON_FILETYPE_PYTHON + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x22842ee4, 0x28a42e84, 0x20042e64, 0x00003ffc, // ICON_FILETYPE_JS + 0x3ff00000, 0x241c2010, 0x2a8c3104, 0x28242454, 0x2ed42004, 0x2a542a54, 0x20042ed4, 0x00003ffc, // ICON_FILETYPE_ICON + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_257 }; // NOTE: A pointer to current icons array should be defined static unsigned int *guiIconsPtr = guiIcons; -#endif // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS +#endif // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS #ifndef RAYGUI_ICON_SIZE #define RAYGUI_ICON_SIZE 0 @@ -1435,10 +1497,12 @@ typedef enum { BORDER = 0, BASE, TEXT, OTHER } GuiPropertyElement; static GuiState guiState = STATE_NORMAL; // Gui global state, if !STATE_NORMAL, forces defined state static Font guiFont = { 0 }; // Gui current font (WARNING: highly coupled to raylib) +static char guiFontName[32] = { 0 }; // Gui font filename, can be loaded from .rgs (Version: >=600) static bool guiLocked = false; // Gui lock state (no inputs processed) static float guiAlpha = 1.0f; // Gui controls transparency static unsigned int guiIconScale = 1; // Gui icon default scale (if icons enabled) +static unsigned int guiIconFontOffsetY = 0; // Gui icon font atlas offset (if icons backed) static bool guiTooltip = false; // Tooltip enabled/disabled static const char *guiTooltipPtr = NULL; // Tooltip string pointer (string provided by user) @@ -1519,22 +1583,22 @@ static int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle( static void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list static unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle() + +static Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font //------------------------------------------------------------------------------- // raylib functions already implemented in raygui //------------------------------------------------------------------------------- static Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value +static Color Fade(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f static int ColorToInt(Color color); // Returns hexadecimal value for a Color static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed' -static char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings static int TextToInteger(const char *text); // Get integer value from text static float TextToFloat(const char *text); // Get float value from text static int GetCodepointNext(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded text static const char *CodepointToUTF8(int codepoint, int *byteSize); // Encode codepoint into UTF-8 text (char array size returned as parameter) - -static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2); // Draw rectangle vertical gradient //------------------------------------------------------------------------------- #endif // RAYGUI_STANDALONE @@ -1542,22 +1606,22 @@ static void DrawRectangleGradientV(int posX, int posY, int width, int height, Co //---------------------------------------------------------------------------------- // Module Internal Functions Declaration //---------------------------------------------------------------------------------- -static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only) - +static int GetLineWidth(const char *text); // Get text line width (stops at '\n' or '\0') static Rectangle GetTextBounds(int control, Rectangle bounds); // Get text bounds considering control bounds static const char *GetTextIcon(const char *text, int *iconId); // Get text icon if provided and move text cursor -static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint); // Gui draw text using default font -static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // Gui draw rectangle using default raygui style +static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint); // Gui draw text using default font +static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // Gui draw rectangle using default raygui style -static char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow); // Split controls text into multiple strings +static char **GuiTextSplit(const char *text, char delimiter, int *count); // Split controls text into multiple strings static Vector3 ConvertHSVtoRGB(Vector3 hsv); // Convert color data from HSV to RGB static Vector3 ConvertRGBtoHSV(Vector3 rgb); // Convert color data from RGB to HSV -static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel() static void GuiTooltip(Rectangle controlRec); // Draw tooltip using control rec position +static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel() +static int GuiFontIconBaking(Image *imFont, Font font, Rectangle *whiteRec); // Update font image atlas to append raygui icons -static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor +static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor //---------------------------------------------------------------------------------- // Gui Setup Functions Definition @@ -1600,7 +1664,7 @@ void GuiSetFont(Font font) { if (font.texture.id > 0) { - // NOTE: If a font is tried to be set but default style has not been lazily loaded first, + // NOTE: If a font is tried to be set but default style has not been lazily loaded first, // it will be overwritten, so default style loading needs to be forced first if (!guiStyleLoaded) GuiLoadStyleDefault(); @@ -1651,7 +1715,7 @@ int GuiWindowBox(Rectangle bounds, const char *title) #define RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT 18 #endif - int result = 0; + int result = RESULT_NONE; //GuiState state = guiState; int statusBarHeight = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT; @@ -1673,11 +1737,15 @@ int GuiWindowBox(Rectangle bounds, const char *title) // Draw control //-------------------------------------------------------------------- GuiPanel(windowPanel, NULL); // Draw window base + + int tempTextAlignment = GuiGetStyle(STATUSBAR, TEXT_ALIGNMENT); + GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); GuiStatusBar(statusBar, title); // Draw window header as status bar + GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, tempTextAlignment); // Draw window close button int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); - int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); GuiSetStyle(BUTTON, BORDER_WIDTH, 1); GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); #if defined(RAYGUI_NO_ICONS) @@ -1689,7 +1757,7 @@ int GuiWindowBox(Rectangle bounds, const char *title) GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); //-------------------------------------------------------------------- - return result; // Window close button clicked: result = 1 + return result; } // Group Box control with text name @@ -1699,7 +1767,7 @@ int GuiGroupBox(Rectangle bounds, const char *text) #define RAYGUI_GROUPBOX_LINE_THICK 1 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Draw control @@ -1724,7 +1792,7 @@ int GuiLine(Rectangle bounds, const char *text) #define RAYGUI_LINE_TEXT_PADDING 4 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; Color color = GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)); @@ -1757,7 +1825,7 @@ int GuiPanel(Rectangle bounds, const char *text) #define RAYGUI_PANEL_BORDER_WIDTH 1 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Text will be drawn as a header bar (if provided) @@ -1773,7 +1841,7 @@ int GuiPanel(Rectangle bounds, const char *text) // Draw control //-------------------------------------------------------------------- - if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar + if (text != NULL) result = GuiStatusBar(statusBar, text); // Draw panel header as status bar GuiDrawRectangle(bounds, RAYGUI_PANEL_BORDER_WIDTH, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)), GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BASE_COLOR_DISABLED : (int)BACKGROUND_COLOR))); @@ -1782,81 +1850,6 @@ int GuiPanel(Rectangle bounds, const char *text) return result; } -// Tab Bar control -// NOTE: Using GuiToggle() for the TABS -int GuiTabBar(Rectangle bounds, char **text, int count, int *active) -{ - #define RAYGUI_TABBAR_ITEM_WIDTH 148 - - int result = -1; - //GuiState state = guiState; - - Rectangle tabBounds = { bounds.x, bounds.y, RAYGUI_TABBAR_ITEM_WIDTH, bounds.height }; - - if (*active < 0) *active = 0; - else if (*active > count - 1) *active = count - 1; - - int offsetX = 0; // Required in case tabs go out of screen - offsetX = (*active + 2)*RAYGUI_TABBAR_ITEM_WIDTH - GetScreenWidth(); - if (offsetX < 0) offsetX = 0; - - bool toggle = false; // Required for individual toggles - - // Draw control - //-------------------------------------------------------------------- - for (int i = 0; i < count; i++) - { - tabBounds.x = bounds.x + (RAYGUI_TABBAR_ITEM_WIDTH + 4)*i - offsetX; - - if (tabBounds.x < GetScreenWidth()) - { - // Draw tabs as toggle controls - int textAlignment = GuiGetStyle(TOGGLE, TEXT_ALIGNMENT); - int textPadding = GuiGetStyle(TOGGLE, TEXT_PADDING); - GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); - GuiSetStyle(TOGGLE, TEXT_PADDING, 8); - - if (i == (*active)) - { - toggle = true; - GuiToggle(tabBounds, text[i], &toggle); - } - else - { - toggle = false; - GuiToggle(tabBounds, text[i], &toggle); - if (toggle) *active = i; - } - - // Close tab with middle mouse button pressed - if (CheckCollisionPointRec(GUI_POINTER_POSITION, tabBounds) && IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON)) result = i; - - GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding); - GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment); - - // Draw tab close button - // NOTE: Only draw close button for current tab: if (CheckCollisionPointRec(mousePosition, tabBounds)) - int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); - int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); - GuiSetStyle(BUTTON, BORDER_WIDTH, 1); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); -#if defined(RAYGUI_NO_ICONS) - if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, "x")) result = i; -#else - if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, GuiIconText(ICON_CROSS_SMALL, NULL))) result = i; -#endif - GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); - } - } - - // Draw tab-bar bottom line - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, 1 }, 0, BLANK, GetColor(GuiGetStyle(TOGGLE, BORDER_COLOR_NORMAL))); - //-------------------------------------------------------------------- - - return result; // Return as result the current TAB closing requested -} - // Scroll Panel control int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view) { @@ -1864,7 +1857,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector #define RAYGUI_MIN_SCROLLBAR_HEIGHT 40 #define RAYGUI_MIN_MOUSE_WHEEL_SPEED 20 - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; Rectangle temp = { 0 }; @@ -1921,7 +1914,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector float horizontalMin = hasHorizontalScrollBar? ((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH); float horizontalMax = hasHorizontalScrollBar? content.width - bounds.width + (float)verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH) - (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)verticalScrollBarWidth : 0) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); - float verticalMin = hasVerticalScrollBar? 0.0f : -1.0f; + float verticalMin = -(float)GuiGetStyle(DEFAULT, BORDER_WIDTH); float verticalMax = hasVerticalScrollBar? content.height - bounds.height + (float)horizontalScrollBarWidth + (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); // Update control @@ -1971,7 +1964,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector // Draw control //-------------------------------------------------------------------- - if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar + if (text != NULL) result = GuiStatusBar(statusBar, text); // Draw panel header as status bar GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background @@ -2018,7 +2011,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector // Label control int GuiLabel(Rectangle bounds, const char *text) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Update control @@ -2037,7 +2030,7 @@ int GuiLabel(Rectangle bounds, const char *text) // Button control, returns true when clicked int GuiButton(Rectangle bounds, const char *text) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Update control @@ -2052,7 +2045,7 @@ int GuiButton(Rectangle bounds, const char *text) if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; - if (GUI_BUTTON_RELEASED) result = 1; + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; } } //-------------------------------------------------------------------- @@ -2065,14 +2058,14 @@ int GuiButton(Rectangle bounds, const char *text) if (state == STATE_FOCUSED) GuiTooltip(bounds); //------------------------------------------------------------------ - return result; // Button pressed: result = 1 + return result; } // Label button control int GuiLabelButton(Rectangle bounds, const char *text) { + int result = RESULT_NONE; GuiState state = guiState; - bool pressed = false; // NOTE: Force bounds.width to be all text float textWidth = (float)GuiGetTextWidth(text); @@ -2090,7 +2083,7 @@ int GuiLabelButton(Rectangle bounds, const char *text) if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; - if (GUI_BUTTON_RELEASED) pressed = true; + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; } } //-------------------------------------------------------------------- @@ -2100,13 +2093,13 @@ int GuiLabelButton(Rectangle bounds, const char *text) GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); //-------------------------------------------------------------------- - return pressed; + return result; } // Toggle Button control int GuiToggle(Rectangle bounds, const char *text, bool *active) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; bool temp = false; @@ -2126,6 +2119,8 @@ int GuiToggle(Rectangle bounds, const char *text, bool *active) { state = STATE_NORMAL; *active = !(*active); + + result = RESULT_CHANGED; } else state = STATE_FOCUSED; } @@ -2154,68 +2149,110 @@ int GuiToggle(Rectangle bounds, const char *text, bool *active) // Toggle Group control int GuiToggleGroup(Rectangle bounds, const char *text, int *active) { - #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEMS) - #define RAYGUI_TOGGLEGROUP_MAX_ITEMS 32 + int result = RESULT_NONE; + + #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE) + #define RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE 256 #endif - int result = 0; - float initBoundsX = bounds.x; + // One toggle group item text + static char itemText[RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE] = { 0 }; + memset(itemText, 0, RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE); int temp = 0; + int prevActive = (active == NULL)? 0 : *active; if (active == NULL) active = &temp; bool toggle = false; // Required for individual toggles - // Get substrings items from text (items pointers) - int rows[RAYGUI_TOGGLEGROUP_MAX_ITEMS] = { 0 }; - int itemCount = 0; - char **items = GuiTextSplit(text, ';', &itemCount, rows); + const char *textPtr = text; + bool itemReady = false; + float initBoundsX = bounds.x; + float initBoundsY = bounds.y; - int prevRow = rows[0]; - - for (int i = 0; i < itemCount; i++) + if (GuiGetStyle(TOGGLE, GROUP_WIDTH_FULL)) { - if (prevRow != rows[i]) - { - bounds.x = initBoundsX; - bounds.y += (bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING)); - prevRow = rows[i]; - } + // Calculate item width considring all horizontal items + // NOTE: bounds.height still considers individual items height + int itemCount = 1; + for (int c = 0; textPtr[c] != '\0'; c++) { if (textPtr[c] == ';') itemCount++; } + bounds.width /= itemCount; + } - if (i == (*active)) + // Text parsing needed to consider potential row and col entries (vertical/horizontal layout) + // when '\n' found move vertically next toggle, when ';' found move horizontally + for (int c = 0, k = 0, itemIndex = 0, row = 0, col = 0, exit = 0; exit == 0; c++) + { + // Process text to get items one by one + // NOTE: Setting columns and rows index properly + if (textPtr[c] == '\n') { - toggle = true; - GuiToggle(bounds, items[i], &toggle); + row++; + col = 0; + itemReady = true; + } + else if (textPtr[c] == ';') + { + col++; + itemReady = true; + } + else if (textPtr[c] == '\0') + { + itemReady = true; + exit = 1; } else { - toggle = false; - GuiToggle(bounds, items[i], &toggle); - if (toggle) *active = i; + itemText[k] = textPtr[c]; + k++; } - bounds.x += (bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING)); + if (itemReady) + { + // When a next item is ready, draw its toggle + if (itemIndex == (*active)) + { + toggle = true; + GuiToggle(bounds, itemText, &toggle); + } + else + { + toggle = false; + GuiToggle(bounds, itemText, &toggle); + if (toggle) *active = itemIndex; + } + + // Calculate next item position + bounds.x = initBoundsX + col*(bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING)); + bounds.y = initBoundsY + row*(bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING)); + + itemIndex++; + itemReady = false; + memset(itemText, 0, k + 1); + k = 0; + } } + if (prevActive != *active) result = RESULT_CHANGED; + return result; } // Toggle Slider control extended int GuiToggleSlider(Rectangle bounds, const char *text, int *active) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; int temp = 0; + int prevActive = (active == NULL)? 0 : *active; if (active == NULL) active = &temp; - //bool toggle = false; // Required for individual toggles - // Get substrings items from text (items pointers) int itemCount = 0; char **items = NULL; - if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL); + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount); Rectangle slider = { 0, // Calculated later depending on the active toggle @@ -2246,6 +2283,8 @@ int GuiToggleSlider(Rectangle bounds, const char *text, int *active) if (*active >= itemCount) *active = 0; slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH) + (*active + 1)*GuiGetStyle(SLIDER, SLIDER_PADDING) + (*active)*slider.width; + + if (prevActive != *active) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -2277,7 +2316,7 @@ int GuiToggleSlider(Rectangle bounds, const char *text, int *active) // Check Box control, returns 1 when state changed int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; bool temp = false; @@ -2316,7 +2355,8 @@ int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) if (GUI_BUTTON_RELEASED) { *checked = !(*checked); - result = 1; + + result = RESULT_CHANGED; } } } @@ -2344,10 +2384,11 @@ int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) // Combo Box control int GuiComboBox(Rectangle bounds, const char *text, int *active) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; int temp = 0; + int prevActive = (active == NULL)? 0 : *active; if (active == NULL) active = &temp; bounds.width -= (GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH) + GuiGetStyle(COMBOBOX, COMBO_BUTTON_SPACING)); @@ -2357,7 +2398,7 @@ int GuiComboBox(Rectangle bounds, const char *text, int *active) // Get substrings items from text (items pointers, lengths and count) int itemCount = 0; - char **items = GuiTextSplit(text, ';', &itemCount, NULL); + char **items = GuiTextSplit(text, ';', &itemCount); if (*active < 0) *active = 0; else if (*active > (itemCount - 1)) *active = itemCount - 1; @@ -2371,16 +2412,18 @@ int GuiComboBox(Rectangle bounds, const char *text, int *active) if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + if (GUI_BUTTON_PRESSED) { *active += 1; if (*active >= itemCount) *active = 0; // Cyclic combobox } - - if (GUI_BUTTON_DOWN) state = STATE_PRESSED; - else state = STATE_FOCUSED; } } + + if (prevActive != *active) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -2409,10 +2452,11 @@ int GuiComboBox(Rectangle bounds, const char *text, int *active) // NOTE: Returns mouse click int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; int temp = 0; + int prevActive = (active == NULL)? 0 : *active; if (active == NULL) active = &temp; int itemSelected = *active; @@ -2423,7 +2467,7 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod // Get substrings items from text (items pointers, lengths and count) int itemCount = 0; - char **items = GuiTextSplit(text, ';', &itemCount, NULL); + char **items = GuiTextSplit(text, ';', &itemCount); Rectangle boundsOpen = bounds; boundsOpen.height = (itemCount + 1)*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); @@ -2523,7 +2567,8 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 }, TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); #else - GuiDrawText(direction? "#121#" : "#120#", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 }, + GuiDrawText(direction? GuiIconText(ICON_ARROW_UP_FILL, NULL) : GuiIconText(ICON_ARROW_DOWN_FILL, NULL), + RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 }, TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); // ICON_ARROW_DOWN_FILL #endif } @@ -2531,8 +2576,9 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod *active = itemSelected; - // TODO: Use result to return more internal states: mouse-press out-of-bounds, mouse-press over selected-item... - return result; // Mouse click: result = 1 + if (prevActive != *active) result = RESULT_CHANGED; + + return result; } // Text Box control @@ -2546,10 +2592,10 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) #define RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY 1 // Frames delay for autocursor movement #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; - bool multiline = false; // TODO: Consider multiline text input + bool multiline = false; int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); Rectangle textBounds = GetTextBounds(TEXTBOX, bounds); @@ -2596,7 +2642,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) { // GLOBAL: Auto-cursor movement logic // NOTE: Keystrokes are handled repeatedly when button is held down for some time - if (GUI_KEY_DOWN(KEY_LEFT) || GUI_KEY_DOWN(KEY_RIGHT) || GUI_KEY_DOWN(KEY_UP) || GUI_KEY_DOWN(KEY_DOWN) || GUI_KEY_DOWN(KEY_BACKSPACE) || GUI_KEY_DOWN(KEY_DELETE)) autoCursorCounter++; + if (GUI_KEY_DOWN(KEY_LEFT) || GUI_KEY_DOWN(KEY_RIGHT) || + GUI_KEY_DOWN(KEY_UP) || GUI_KEY_DOWN(KEY_DOWN) || + GUI_KEY_DOWN(KEY_BACKSPACE) || GUI_KEY_DOWN(KEY_DELETE)) autoCursorCounter++; else autoCursorCounter = 0; bool autoCursorShouldTrigger = (autoCursorCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN) && ((autoCursorCounter % RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0); @@ -2654,6 +2702,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) textBoxCursorIndex += pasteLength; textLength += pasteLength; text[textLength] = '\0'; + + //result = RESULT_CHANGED; } } } @@ -2672,6 +2722,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) // Make sure text last character is EOL text[textLength] = '\0'; + + //result = RESULT_CHANGED; } // Move cursor to start @@ -2694,8 +2746,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) bool puctuation = ispunct(nextCodepoint & 0xff); while (offset < textLength) { - if ((puctuation && !ispunct(nextCodepoint & 0xff)) || (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff)))) - break; + if ((puctuation && !ispunct(nextCodepoint & 0xff)) || + (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff)))) break; + offset += nextCodepointSize; accCodepointSize += nextCodepointSize; nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); @@ -2715,9 +2768,11 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) for (int i = offset; i <= textLength; i++) text[i - accCodepointSize] = text[i]; textLength -= accCodepointSize; - } - else if ((textLength > textBoxCursorIndex) && (GUI_KEY_PRESSED(KEY_DELETE) || (GUI_KEY_DOWN(KEY_DELETE) && autoCursorShouldTrigger))) + //result = RESULT_CHANGED; + } + else if ((textLength > textBoxCursorIndex) && (GUI_KEY_PRESSED(KEY_DELETE) || + (GUI_KEY_DOWN(KEY_DELETE) && autoCursorShouldTrigger))) { // Delete single codepoint from text, after current cursor position @@ -2728,10 +2783,13 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) for (int i = textBoxCursorIndex + nextCodepointSize; i <= textLength; i++) text[i - nextCodepointSize] = text[i]; textLength -= nextCodepointSize; + + //result = RESULT_CHANGED; } // Delete related codepoints from text, before current cursor position - if ((textBoxCursorIndex > 0) && GUI_KEY_PRESSED(KEY_BACKSPACE) && (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) + if ((textBoxCursorIndex > 0) && GUI_KEY_PRESSED(KEY_BACKSPACE) && + (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) { int offset = textBoxCursorIndex; int accCodepointSize = 0; @@ -2754,7 +2812,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) while (offset > 0) { prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize); - if ((puctuation && !ispunct(prevCodepoint & 0xff)) || (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break; + if ((puctuation && !ispunct(prevCodepoint & 0xff)) || + (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break; offset -= prevCodepointSize; accCodepointSize += prevCodepointSize; @@ -2765,8 +2824,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) textLength -= accCodepointSize; textBoxCursorIndex -= accCodepointSize; - } + //result = RESULT_CHANGED; + } else if ((textBoxCursorIndex > 0) && (GUI_KEY_PRESSED(KEY_BACKSPACE) || (GUI_KEY_DOWN(KEY_BACKSPACE) && autoCursorShouldTrigger))) { // Delete single codepoint from text, before current cursor position @@ -2780,6 +2840,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) textLength -= prevCodepointSize; textBoxCursorIndex -= prevCodepointSize; + + //result = RESULT_CHANGED; } // Move cursor position with keys @@ -2862,7 +2924,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) } // Move cursor position with mouse - if (CheckCollisionPointRec(mousePosition, textBounds)) // Mouse hover text + if (CheckCollisionPointRec(mousePosition, textBounds)) { float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/(float)guiFont.baseSize; int codepointIndex = 0; @@ -2915,7 +2977,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) { textBoxCursorIndex = 0; // GLOBAL: Reset the shared cursor index autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes - result = 1; + + //*editMode = false; + result = RESULT_PRESSED; } } else @@ -2928,7 +2992,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) { textBoxCursorIndex = textLength; // GLOBAL: Place cursor index to the end of current text autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes - result = 1; + + //*editMode = true; + result = RESULT_PRESSED; } } } @@ -2963,7 +3029,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) else if (state == STATE_FOCUSED) GuiTooltip(bounds); //-------------------------------------------------------------------- - return result; // Mouse button pressed: result = 1 + return result; } /* @@ -3061,21 +3127,24 @@ int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); //-------------------------------------------------------------------- + //if (tempValue != *value) result = RESULT_CHANGED; // WARNING: Stops editing + *value = tempValue; + return result; } // Value Box control, updates input text with numbers -// NOTE: Requires static variables: frameCounter int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) { #if !defined(RAYGUI_VALUEBOX_MAX_CHARS) #define RAYGUI_VALUEBOX_MAX_CHARS 32 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; + //int prevValue = *value; char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = { 0 }; snprintf(textValue, RAYGUI_VALUEBOX_MAX_CHARS + 1, "%i", *value); @@ -3162,7 +3231,7 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in if (*value > maxValue) *value = maxValue; else if (*value < minValue) *value = minValue; - result = 1; + result = RESULT_PRESSED; } } else @@ -3173,10 +3242,13 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in if (CheckCollisionPointRec(mousePoint, bounds)) { state = STATE_FOCUSED; - if (GUI_BUTTON_PRESSED) result = 1; + + if (GUI_BUTTON_PRESSED) result = RESULT_PRESSED; } } } + + //if (prevValue != *value) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3207,18 +3279,16 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in } // Floating point Value Box control, updates input val_str with numbers -// NOTE: Requires static variables: frameCounter int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode) { #if !defined(RAYGUI_VALUEBOX_MAX_CHARS) #define RAYGUI_VALUEBOX_MAX_CHARS 32 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; - //char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0"; - //snprintf(textValue, sizeof(textValue), "%2.2f", *value); + //float prevValue = *value; Rectangle textBounds = { 0 }; if (text != NULL) @@ -3303,17 +3373,21 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float if (valueHasChanged) *value = TextToFloat(textValue); - if ((GUI_KEY_PRESSED(KEY_ENTER) || GUI_KEY_PRESSED(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && GUI_BUTTON_PRESSED)) result = 1; + if ((GUI_KEY_PRESSED(KEY_ENTER) || GUI_KEY_PRESSED(KEY_KP_ENTER)) || + (!CheckCollisionPointRec(mousePoint, bounds) && GUI_BUTTON_PRESSED)) result = RESULT_PRESSED; } else { if (CheckCollisionPointRec(mousePoint, bounds)) { state = STATE_FOCUSED; - if (GUI_BUTTON_PRESSED) result = 1; + + if (GUI_BUTTON_PRESSED) result = RESULT_PRESSED; } } } + + //if (prevValue != *value) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3336,8 +3410,7 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float } // Draw text label if provided - GuiDrawText(text, textBounds, - (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, + GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); //-------------------------------------------------------------------- @@ -3348,12 +3421,13 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float // NOTE: Other GuiSlider*() controls use this one int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; float temp = (maxValue - minValue)/2.0f; if (value == NULL) value = &temp; - float oldValue = *value; + + float prevValue = *value; int sliderWidth = GuiGetStyle(SLIDER, SLIDER_WIDTH); @@ -3404,10 +3478,6 @@ int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, flo else if (*value < minValue) *value = minValue; } - // Control value change check - if (oldValue == *value) result = 0; - else result = 1; - // Slider bar limits check float sliderValue = (((*value - minValue)/(maxValue - minValue))*(bounds.width - sliderWidth - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))); if (sliderWidth > 0) // Slider @@ -3423,6 +3493,8 @@ int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, flo slider.width = sliderValue; if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH); } + + if (prevValue != *value) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3465,7 +3537,7 @@ int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, flo // Slider Bar control extended, returns selected value int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) { - int result = 0; + int result = RESULT_NONE; int preSliderWidth = GuiGetStyle(SLIDER, SLIDER_WIDTH); GuiSetStyle(SLIDER, SLIDER_WIDTH, 0); result = GuiSlider(bounds, textLeft, textRight, value, minValue, maxValue); @@ -3477,11 +3549,12 @@ int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, // Progress Bar control extended, shows current progress value int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; float temp = (maxValue - minValue)/2.0f; if (value == NULL) value = &temp; + float prevValue = *value; // Progress bar Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), @@ -3494,6 +3567,8 @@ int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight // WARNING: Working with floats could lead to rounding issues if ((state != STATE_DISABLED)) progress.width = ((float)*value/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)); + + if (prevValue != *value) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3564,9 +3639,26 @@ int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight // Status Bar control int GuiStatusBar(Rectangle bounds, const char *text) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check checkbox state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + //if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + //else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; + } + } + //-------------------------------------------------------------------- + // Draw control //-------------------------------------------------------------------- GuiDrawRectangle(bounds, GuiGetStyle(STATUSBAR, BORDER_WIDTH), GetColor(GuiGetStyle(STATUSBAR, BORDER + (state*3))), GetColor(GuiGetStyle(STATUSBAR, BASE + (state*3)))); @@ -3579,7 +3671,7 @@ int GuiStatusBar(Rectangle bounds, const char *text) // Dummy rectangle control, intended for placeholding int GuiDummyRec(Rectangle bounds, const char *text) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Update control @@ -3593,6 +3685,8 @@ int GuiDummyRec(Rectangle bounds, const char *text) { if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; } } //-------------------------------------------------------------------- @@ -3609,25 +3703,26 @@ int GuiDummyRec(Rectangle bounds, const char *text) // List View control int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active) { - int result = 0; + int result = RESULT_NONE; int itemCount = 0; char **items = NULL; - if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL); + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount); result = GuiListViewEx(bounds, items, itemCount, scrollIndex, active, NULL); return result; } -// List View control with extended parameters +// List View control using text entries list and returning focus entry int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; int itemFocused = (focus == NULL)? -1 : *focus; int itemSelected = (active == NULL)? -1 : *active; + int prevActive = (active == NULL)? 0 : *active; // Check if scroll bar is needed bool useScrollBar = false; @@ -3765,35 +3860,132 @@ int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, in if (focus != NULL) *focus = itemFocused; if (scrollIndex != NULL) *scrollIndex = startIndex; + if (prevActive != *active) result = RESULT_CHANGED; + return result; } -// Color Panel control - Color (RGBA) variant +// Tab Bar control +int GuiTabBar(Rectangle bounds, const char *text, int *hscroll, int *active) +{ + int result = RESULT_NONE; + int itemCount = 0; + char **items = NULL; + + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount); + + result = GuiTabBarEx(bounds, items, itemCount, hscroll, active, NULL); + + return result; +} + +// Tab Bar control, using text entries list and returning focus entry +// NOTE: In case of tab close result, consider focused tab +// TODO: Reeplace GuiToggle() usage for custom implementation for the TABS +int GuiTabBarEx(Rectangle bounds, char **text, int count, int *hscroll, int *active, int *focus) +{ + int result = RESULT_NONE; + //GuiState state = guiState; + + int tabItemsWidth = GuiGetStyle(TABBAR, TAB_ITEMS_WIDTH); + Rectangle tabBounds = { bounds.x, bounds.y, (float)tabItemsWidth, bounds.height }; + + if (*active < 0) *active = 0; + else if (*active > count - 1) *active = count - 1; + + int prevActive = (active == NULL)? 0 : *active; + + int offsetX = 0; // Required in case tabs go out of screen + offsetX = (*active*tabItemsWidth) - GetScreenWidth(); + if (offsetX < 0) offsetX = 0; + + bool toggle = false; // Required for individual toggles + + // Draw control + //-------------------------------------------------------------------- + //if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) // TODO: Support disabled + + for (int i = 0; i < count; i++) + { + tabBounds.x = bounds.x + (tabItemsWidth + 4)*i + offsetX; + + if (tabBounds.x < GetScreenWidth()) + { + // Draw tabs as toggle controls + int textAlignment = GuiGetStyle(TOGGLE, TEXT_ALIGNMENT); + int textPadding = GuiGetStyle(TOGGLE, TEXT_PADDING); + GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(TOGGLE, TEXT_PADDING, 8); + + if (i == (*active)) + { + toggle = true; + GuiToggle(tabBounds, text[i], &toggle); + } + else + { + toggle = false; + GuiToggle(tabBounds, text[i], &toggle); + if (toggle) *active = i; + } + + // Close tab with middle mouse button pressed + if (CheckCollisionPointRec(GUI_POINTER_POSITION, tabBounds) && GUI_BUTTON_PRESSED_MID) result = RESULT_TAB_CLOSE; + + GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding); + GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment); + + if (GuiGetStyle(TABBAR, TAB_CLOSE_BUTTON)) + { + // Draw tab close button + // NOTE: Only draw close button for current tab: if (CheckCollisionPointRec(mousePosition, tabBounds)) + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 1); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); +#if defined(RAYGUI_NO_ICONS) + if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, "x")) result = RESULT_TAB_CLOSE; +#else + if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, + GuiIconText(ICON_CROSS_SMALL, NULL))) result = RESULT_TAB_CLOSE; +#endif + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); + } + } + } + + // Draw tab-bar bottom line + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, 1 }, 0, BLANK, GetColor(GuiGetStyle(TABBAR, BORDER_COLOR_NORMAL))); + //-------------------------------------------------------------------- + + // NOTE: In case of tab close result, consider focused tab + if ((result != RESULT_TAB_CLOSE) && (prevActive != *active)) result = RESULT_CHANGED; + + return result; +} + +// Color Panel control int GuiColorPanel(Rectangle bounds, const char *text, Color *color) { - int result = 0; + int result = RESULT_NONE; Vector3 vcolor = { (float)color->r/255.0f, (float)color->g/255.0f, (float)color->b/255.0f }; Vector3 hsv = ConvertRGBtoHSV(vcolor); - Vector3 prevHsv = hsv; // workaround to see if GuiColorPanelHSV modifies the hsv + Vector3 prevHsv = hsv; // NOTE: Workaround to see if GuiColorPanelHSV() modifies the hsv - GuiColorPanelHSV(bounds, text, &hsv); + result = GuiColorPanelHSV(bounds, text, &hsv); // Check if the hsv was changed, only then change the color // This is required, because the Color->HSV->Color conversion has precision errors // Thus the assignment from HSV to Color should only be made, if the HSV has a new user-entered value // Otherwise GuiColorPanel would often modify it's color without user input - // TODO: GuiColorPanelHSV could return 1 if the slider was dragged, to simplify this check - if (hsv.x != prevHsv.x || hsv.y != prevHsv.y || hsv.z != prevHsv.z) + if ((hsv.x != prevHsv.x) || (hsv.y != prevHsv.y) || (hsv.z != prevHsv.z)) { Vector3 rgb = ConvertHSVtoRGB(hsv); - - // NOTE: Vector3ToColor() only available on raylib 1.8.1 - *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x), - (unsigned char)(255.0f*rgb.y), - (unsigned char)(255.0f*rgb.z), - color->a }; + *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x), (unsigned char)(255.0f*rgb.y), (unsigned char)(255.0f*rgb.z), color->a }; } + return result; } @@ -3805,8 +3997,10 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) #define RAYGUI_COLORBARALPHA_CHECKED_SIZE 10 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; + + float prevAlpha = *alpha; Rectangle selector = { (float)bounds.x + (*alpha)*bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.y - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT), @@ -3853,6 +4047,8 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) else state = STATE_FOCUSED; } } + + if (prevAlpha != *alpha) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3893,8 +4089,10 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) // float GuiColorBarLuminance() [BLACK->WHITE] int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; + + float prevHue = *hue; Rectangle selector = { (float)bounds.x - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)bounds.y + (*hue)/360.0f*bounds.height - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2, (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT) }; // Update control @@ -3949,6 +4147,8 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) }*/ } } + + if (prevHue != *hue) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3956,15 +4156,32 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) if (state != STATE_DISABLED) { // Draw hue bar:color bars - // TODO: Use directly DrawRectangleGradientEx(bounds, color1, color2, color2, color1); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + bounds.height/6), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 2*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 3*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 4*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 5*(bounds.height/6)), (int)bounds.width, (int)(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha)); + // NOTE: Using DrawRectangleGradientEx(bounds, color1, color2, color2, color1); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 1*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 2*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 3*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 4*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 5*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha)); + } + else + { + DrawRectangleGradientEx(bounds, + Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), + Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha)); } - else DrawRectangleGradientV((int)bounds.x, (int)bounds.y, (int)bounds.width, (int)bounds.height, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha)); GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); @@ -3984,12 +4201,12 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) // NOTE: this picker converts RGB to HSV, which can cause the Hue control to jump. If you have this problem, consider using the HSV variant instead int GuiColorPicker(Rectangle bounds, const char *text, Color *color) { - int result = 0; + int result = RESULT_NONE; Color temp = { 200, 0, 0, 255 }; if (color == NULL) color = &temp; - GuiColorPanel(bounds, NULL, color); + result = GuiColorPanel(bounds, NULL, color); Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; //Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) }; @@ -3997,7 +4214,7 @@ int GuiColorPicker(Rectangle bounds, const char *text, Color *color) // NOTE: this conversion can cause low hue-resolution, if the r, g and b value are very similar, which causes the hue bar to shift around when only the GuiColorPanel is used Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ (*color).r/255.0f, (*color).g/255.0f, (*color).b/255.0f }); - GuiColorBarHue(boundsHue, NULL, &hsv.x); + if (result != RESULT_CHANGED) result = GuiColorBarHue(boundsHue, NULL, &hsv.x); //color.a = (unsigned char)(GuiColorBarAlpha(boundsAlpha, (float)color.a/255.0f)*255.0f); Vector3 rgb = ConvertHSVtoRGB(hsv); @@ -4016,7 +4233,7 @@ int GuiColorPicker(Rectangle bounds, const char *text, Color *color) // NOTE: bounds define GuiColorPanelHSV() size int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) { - int result = 0; + int result = RESULT_NONE; Vector3 tempHsv = { 0 }; @@ -4027,11 +4244,11 @@ int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) colorHsv = &tempHsv; } - GuiColorPanelHSV(bounds, NULL, colorHsv); + result = GuiColorPanelHSV(bounds, NULL, colorHsv); - const Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; + Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; - GuiColorBarHue(boundsHue, NULL, &colorHsv->x); + if (result == RESULT_NONE) result = GuiColorBarHue(boundsHue, NULL, &colorHsv->x); return result; } @@ -4039,10 +4256,11 @@ int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) // Color Panel control - HSV variant int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; - Vector2 pickerSelector = { 0 }; + Vector3 prevColorHsv = *colorHsv; + Vector2 pickerSelector = { 0 }; const Color colWhite = { 255, 255, 255, 255 }; const Color colBlack = { 0, 0, 0, 255 }; @@ -4051,9 +4269,7 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) Vector3 maxHue = { colorHsv->x, 1.0f, 1.0f }; Vector3 rgbHue = ConvertHSVtoRGB(maxHue); - Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x), - (unsigned char)(255.0f*rgbHue.y), - (unsigned char)(255.0f*rgbHue.z), 255 }; + Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x), (unsigned char)(255.0f*rgbHue.y), (unsigned char)(255.0f*rgbHue.z), 255 }; // Update control //-------------------------------------------------------------------- @@ -4077,12 +4293,11 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) // Calculate color from picker Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y }; - colorPick.x /= (float)bounds.width; // Get normalized value on x - colorPick.y /= (float)bounds.height; // Get normalized value on y + colorPick.x /= (float)bounds.width; // Get normalized value on x + colorPick.y /= (float)bounds.height; // Get normalized value on y colorHsv->y = colorPick.x; colorHsv->z = 1.0f - colorPick.y; - } } else @@ -4112,6 +4327,10 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) else state = STATE_FOCUSED; } } + + if ((prevColorHsv.x != colorHsv->x) || + (prevColorHsv.y != colorHsv->y) || + (prevColorHsv.z != colorHsv->z)) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -4137,7 +4356,8 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) } // Message Box control -int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons) +// NOTE: Button pressed is returned through btnActive parameter, 0 for window close button +int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *btnText, int *btnActive) { #if !defined(RAYGUI_MESSAGEBOX_BUTTON_HEIGHT) #define RAYGUI_MESSAGEBOX_BUTTON_HEIGHT 24 @@ -4146,10 +4366,10 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons #define RAYGUI_MESSAGEBOX_BUTTON_PADDING 12 #endif - int result = -1; // Returns clicked button from buttons list, 0 refers to closed window button + int result = RESULT_NONE; int buttonCount = 0; - char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL); + char **btnTextList = GuiTextSplit(btnText, ';', &buttonCount); Rectangle buttonBounds = { 0 }; buttonBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING; buttonBounds.y = bounds.y + bounds.height - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT - RAYGUI_MESSAGEBOX_BUTTON_PADDING; @@ -4166,7 +4386,11 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons // Draw control //-------------------------------------------------------------------- - if (GuiWindowBox(bounds, title)) result = 0; + if (GuiWindowBox(bounds, title) == RESULT_PRESSED) + { + *btnActive = 0; + result = RESULT_PRESSED; + } int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); @@ -4178,7 +4402,11 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons for (int i = 0; i < buttonCount; i++) { - if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1; + if (GuiButton(buttonBounds, btnTextList[i])) + { + *btnActive = i + 1; + result = RESULT_PRESSED; + } buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING); } @@ -4188,8 +4416,9 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons return result; } -// Text Input Box control, ask for text -int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive) +// Text Input Box control +// NOTE: Button pressed is returned through btnActive parameter, 0 for window close button +int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, char *text, int textSize, const char *btnText, int *btnActive, bool *secretViewActive) { #if !defined(RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT) #define RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT 24 @@ -4201,14 +4430,14 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co #define RAYGUI_TEXTINPUTBOX_HEIGHT 26 #endif + int result = RESULT_NONE; + // Used to enable text edit mode // WARNING: No more than one GuiTextInputBox() should be open at the same time static bool textEditMode = false; - int result = -1; - int buttonCount = 0; - char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL); + char **btnTextList = GuiTextSplit(btnText, ';', &buttonCount); Rectangle buttonBounds = { 0 }; buttonBounds.x = bounds.x + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; buttonBounds.y = bounds.y + bounds.height - RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; @@ -4238,7 +4467,11 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co // Draw control //-------------------------------------------------------------------- - if (GuiWindowBox(bounds, title)) result = 0; + if (GuiWindowBox(bounds, title) == RESULT_PRESSED) + { + *btnActive = 0; + result = RESULT_PRESSED; + } // Draw message if available if (message != NULL) @@ -4256,13 +4489,20 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co { static char stars[] = "****************"; if (GuiTextBox(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x, textBoxBounds.y, textBoxBounds.width - 4 - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.height }, - ((*secretViewActive == 1) || textEditMode)? text : stars, textMaxSize, textEditMode)) textEditMode = !textEditMode; + ((*secretViewActive == 1) || textEditMode)? text : stars, textSize, textEditMode) == RESULT_PRESSED) textEditMode = !textEditMode; - GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, (*secretViewActive == 1)? "#44#" : "#45#", secretViewActive); +#if defined(RAYGUI_NO_ICONS) + GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, + (*secretViewActive == 1)? "O" : "*", secretViewActive); +#else + GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, + (*secretViewActive == 1)? GuiIconText(ICON_EYE_ON, NULL) : GuiIconText(ICON_EYE_OFF, NULL), secretViewActive); +#endif } else { - if (GuiTextBox(textBoxBounds, text, textMaxSize, textEditMode)) textEditMode = !textEditMode; + if (GuiTextBox(textBoxBounds, text, textSize, textEditMode) == RESULT_PRESSED) + textEditMode = !textEditMode; } GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, prevTextBoxAlignment); @@ -4272,16 +4512,21 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co for (int i = 0; i < buttonCount; i++) { - if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1; + if (GuiButton(buttonBounds, btnTextList[i])) + { + *btnActive = i + 1; + result = RESULT_PRESSED; + } + buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING); } - if (result >= 0) textEditMode = false; + if (result == RESULT_PRESSED) textEditMode = false; GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevBtnTextAlignment); //-------------------------------------------------------------------- - return result; // Result is the pressed button index + return result; } // Grid control @@ -4295,7 +4540,7 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect #define RAYGUI_GRID_ALPHA 0.15f #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; Vector2 mousePoint = GUI_POINTER_POSITION; @@ -4316,6 +4561,8 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect // NOTE: Cell values must be the upper left of the cell the mouse is in currentMouseCell.x = floorf((mousePoint.x - bounds.x)/spacing); currentMouseCell.y = floorf((mousePoint.y - bounds.y)/spacing); + + result = RESULT_PRESSED; } } //-------------------------------------------------------------------- @@ -4342,6 +4589,7 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect } if (mouseCell != NULL) *mouseCell = currentMouseCell; + return result; } @@ -4385,11 +4633,16 @@ void GuiLoadStyle(const char *fileName) int controlId = 0; int propertyId = 0; unsigned int propertyValue = 0; + unsigned int version = 0; while (!feof(rgsFile)) { switch (buffer[0]) { + case 'v': + { + sscanf(buffer, "v %d", &version); + } case 'p': { // Style property: p @@ -4400,12 +4653,17 @@ void GuiLoadStyle(const char *fileName) } break; case 'f': { - // Style font: f + // Style font: f int fontSize = 0; - char charmapFileName[256] = { 0 }; - char fontFileName[256] = { 0 }; - sscanf(buffer, "f %d %s %[^\r\n]s", &fontSize, charmapFileName, fontFileName); + char charmapFileName[32] = { 0 }; + char fontFileName[32] = { 0 }; + + if (version >= 600) sscanf(buffer, "f %d %31s %31[^\r\n]s", &fontSize, fontFileName, charmapFileName); + else sscanf(buffer, "f %d %31s %31[^\r\n]s", &fontSize, charmapFileName, fontFileName); + + // GLOBAL: Copy font file name into guiFontName + snprintf(guiFontName, 32, "%s", fontFileName); Font font = { 0 }; int *codepoints = NULL; @@ -4481,6 +4739,318 @@ void GuiLoadStyle(const char *fileName) } } +// Load style from memory +// WARNING: Binary files only +void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize) +{ + // Style File Structure (.rgs) + // ------------------------------------------------------ + // Offset | Size | Type | Description + // ------------------------------------------------------ + // 0 | 4 | char | Signature: "rGS " + // 4 | 2 | short | Version: 200, 400, 600 + // 6 | 2 | short | reserved + // 8 | 4 | int | Num properties (only changed ones from default style) + + // Properties Data (8 bytes per property) + // WARNING: Only properties required that differ from default (light) internal style + // foreach (property) + // { + // 8+8*i | 2 | short | ControlId + // 8+8*i | 2 | short | PropertyId + // 8+8*i | 4 | int | PropertyValue + // } + + // Custom Font Data : Parameters (64 bytes) + // ... | 4 | int | Font data size (0 - no font, no more fields added!) + // ... | 32 | char | Font filename (with extension) - VERSION: >=600 + // ... | 4 | int | Font base size + // ... | 4 | int | Font glyph count [glyphCount] + // ... | 4 | int | Font type (0-NORMAL, 1-SDF) + // ... | 16 | Rectangle | Font white rectangle + + // Custom Font Data : Image (20 bytes + imData) + // NOTE: Font image atlas is always converted to GRAY+ALPHA + // and atlas image data can be compressed (DEFLATE) + // ... | 4 | int | Image data size (uncompressed) + // ... | 4 | int | Image data size (compressed) + // ... | 4 | int | Image width + // ... | 4 | int | Image height + // ... | 4 | int | Image format: GRAY+ALPHA (expected) + // ... | imSize | byte | Image data (comp or uncomp) + + // Custom Font Data : Recs (32 bytes*glyphCount) + // NOTE: Font recs data can be compressed (DEFLATE) + // ... | 4 | int | Recs data compressed size (0 - not compressed, 1-compressed) - VERSION: >=400 + // + // if (compRecsSize == 0) + // { + // NOTE: Uncompressed size can be calculated: (glyphCount*16 byte) + // foreach (glyph) + // { + // ... | 16 | Rectangle | Glyph rectangle (in image) + // } + // } + // else + // { + // ... | compRecsSize | byte | Rectangles data + // } + // + + // Custom Font Data : Glyph Info (32 bytes*glyphCount) + // NOTE: Font glyphs info data can be compressed (DEFLATE) + // ... | 4 | int | Glyphs data compressed size (0 - not compressed) - VERSION: >=400 + // + // if (compGlyphsSize == 0) + // { + // NOTE: Uncompressed size can be calculated: (glyphCount*16 byte) + // foreach (glyph) + // { + // ... | 4 | int | Glyph value + // ... | 4 | int | Glyph offset X + // ... | 4 | int | Glyph offset Y + // ... | 4 | int | Glyph advance X + // } + // } + // else + // { + // ... | compGlyphsSize | byte | Glyphs data + // } + // ------------------------------------------------------ + + unsigned char *fileDataPtr = (unsigned char *)fileData; + + char signature[5] = { 0 }; + short version = 0; + short reserved = 0; + int propertyCount = 0; + + memcpy(signature, fileDataPtr, 4); + memcpy(&version, fileDataPtr + 4, sizeof(short)); + memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short)); + memcpy(&propertyCount, fileDataPtr + 4 + 2 + 2, sizeof(int)); + fileDataPtr += 12; + + if ((signature[0] == 'r') && + (signature[1] == 'G') && + (signature[2] == 'S') && + (signature[3] == ' ')) + { + short controlId = 0; + short propertyId = 0; + unsigned int propertyValue = 0; + + for (int i = 0; i < propertyCount; i++) + { + memcpy(&controlId, fileDataPtr, sizeof(short)); + memcpy(&propertyId, fileDataPtr + 2, sizeof(short)); + memcpy(&propertyValue, fileDataPtr + 2 + 2, sizeof(unsigned int)); + fileDataPtr += 8; + + if (controlId == 0) // DEFAULT control + { + // If a DEFAULT property is loaded, it is propagated to all controls + // NOTE: All DEFAULT properties should be defined first in the file + GuiSetStyle(0, (int)propertyId, propertyValue); + + if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int j = 1; j < RAYGUI_MAX_CONTROLS; j++) GuiSetStyle(j, (int)propertyId, propertyValue); + } + else GuiSetStyle((int)controlId, (int)propertyId, propertyValue); + } + + // Load custom font if available + // NOTE: Font texture loading requires raylib + int fontDataSize = 0; + memcpy(&fontDataSize, fileDataPtr, sizeof(int)); + fileDataPtr += 4; + + if (fontDataSize > 0) + { + Font font = { 0 }; + int fontType = 0; // 0-Normal, 1-SDF + + // WARNING: Version 600 adds 32 bytes for the font filename (with extension) + if (version >= 600) + { + // GLOBAL: Copy font file name into guiFontName + memcpy(guiFontName, fileDataPtr, 32); + fileDataPtr += 32; + } + else memset(guiFontName, 0, 32); + + memcpy(&font.baseSize, fileDataPtr, sizeof(int)); + memcpy(&font.glyphCount, fileDataPtr + 4, sizeof(int)); + memcpy(&fontType, fileDataPtr + 4 + 4, sizeof(int)); + fileDataPtr += 12; + + // Load font white rectangle + Rectangle fontWhiteRec = { 0 }; + memcpy(&fontWhiteRec, fileDataPtr, sizeof(Rectangle)); + fileDataPtr += 16; + + // Load font image parameters + int fontImageUncompSize = 0; + int fontImageCompSize = 0; + memcpy(&fontImageUncompSize, fileDataPtr, sizeof(int)); + memcpy(&fontImageCompSize, fileDataPtr + 4, sizeof(int)); + fileDataPtr += 8; + + Image imFont = { 0 }; + imFont.mipmaps = 1; + memcpy(&imFont.width, fileDataPtr, sizeof(int)); + memcpy(&imFont.height, fileDataPtr + 4, sizeof(int)); + memcpy(&imFont.format, fileDataPtr + 4 + 4, sizeof(int)); + fileDataPtr += 12; + + if ((fontImageCompSize > 0) && (fontImageCompSize != fontImageUncompSize)) + { + // Compressed font atlas image data (DEFLATE), it requires DecompressData() + int dataUncompSize = 0; + unsigned char *compData = (unsigned char *)RAYGUI_CALLOC(fontImageCompSize, sizeof(unsigned char)); + memcpy(compData, fileDataPtr, fontImageCompSize); + fileDataPtr += fontImageCompSize; + + imFont.data = DecompressData(compData, fontImageCompSize, &dataUncompSize); + + // Security check, dataUncompSize must match the provided fontImageUncompSize + if (dataUncompSize != fontImageUncompSize) RAYGUI_LOG("WARNING: Uncompressed font atlas image data could be corrupted"); + + RAYGUI_FREE(compData); + } + else + { + // Font atlas image data is not compressed + imFont.data = (unsigned char *)RAYGUI_CALLOC(fontImageUncompSize, sizeof(unsigned char)); + memcpy(imFont.data, fileDataPtr, fontImageUncompSize); + fileDataPtr += fontImageUncompSize; + } + + // Load font recs data (glyphs position and size in the image atlas) + int recsDataSize = font.glyphCount*sizeof(Rectangle); + int recsDataCompressedSize = 0; + + // WARNING: Version 400 adds the compression size parameter + if (version >= 400) + { + // RGS files version 400 support compressed recs data + memcpy(&recsDataCompressedSize, fileDataPtr, sizeof(int)); + fileDataPtr += sizeof(int); + } + + if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize)) + { + // Recs data is compressed, uncompress it + unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_CALLOC(recsDataCompressedSize, sizeof(unsigned char)); + + memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize); + fileDataPtr += recsDataCompressedSize; + + int recsDataUncompSize = 0; + font.recs = (Rectangle *)DecompressData(recsDataCompressed, recsDataCompressedSize, &recsDataUncompSize); + + // Security check, data uncompressed size must match the expected original data size + if (recsDataUncompSize != recsDataSize) RAYGUI_LOG("WARNING: Uncompressed font recs data could be corrupted"); + + RAYGUI_FREE(recsDataCompressed); + } + else + { + // Recs data is uncompressed + font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle)); + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.recs[i], fileDataPtr, sizeof(Rectangle)); + fileDataPtr += sizeof(Rectangle); + } + } + + // Load font glyphs info data + int glyphsDataSize = font.glyphCount*16; // 16 bytes data per glyph + int glyphsDataCompressedSize = 0; + + // WARNING: Version 400 adds the compression size parameter + if (version >= 400) + { + // RGS files version 400 support compressed glyphs data + memcpy(&glyphsDataCompressedSize, fileDataPtr, sizeof(int)); + fileDataPtr += sizeof(int); + } + + // Allocate required glyphs space to fill with data + font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo)); + + if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize)) + { + // Glyphs data is compressed, uncompress it + unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_CALLOC(glyphsDataCompressedSize, sizeof(unsigned char)); + + memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize); + fileDataPtr += glyphsDataCompressedSize; + + int glyphsDataUncompSize = 0; + unsigned char *glyphsDataUncomp = DecompressData(glypsDataCompressed, glyphsDataCompressedSize, &glyphsDataUncompSize); + + // Security check, data uncompressed size must match the expected original data size + if (glyphsDataUncompSize != glyphsDataSize) RAYGUI_LOG("WARNING: Uncompressed font glyphs data could be corrupted"); + + unsigned char *glyphsDataUncompPtr = glyphsDataUncomp; + + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.glyphs[i].value, glyphsDataUncompPtr, sizeof(int)); + memcpy(&font.glyphs[i].offsetX, glyphsDataUncompPtr + 4, sizeof(int)); + memcpy(&font.glyphs[i].offsetY, glyphsDataUncompPtr + 8, sizeof(int)); + memcpy(&font.glyphs[i].advanceX, glyphsDataUncompPtr + 12, sizeof(int)); + glyphsDataUncompPtr += 16; + } + + RAYGUI_FREE(glypsDataCompressed); + RAYGUI_FREE(glyphsDataUncomp); + } + else + { + // Glyphs data is uncompressed + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.glyphs[i].value, fileDataPtr, sizeof(int)); + memcpy(&font.glyphs[i].offsetX, fileDataPtr + 4, sizeof(int)); + memcpy(&font.glyphs[i].offsetY, fileDataPtr + 8, sizeof(int)); + memcpy(&font.glyphs[i].advanceX, fileDataPtr + 12, sizeof(int)); + fileDataPtr += 16; + } + } + +#if defined(RAYGUI_FONT_ICONS_BAKING) + // Font atlas image icons baking + Rectangle updatedWhiteRec = { 0 }; + guiIconFontOffsetY = GuiFontIconBaking(&imFont, font, &updatedWhiteRec); + if (guiIconFontOffsetY > 0) fontWhiteRec = updatedWhiteRec; +#endif + +#if !defined(RAYGUI_STANDALONE) + // Load texture from image + if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture); + font.texture = LoadTextureFromImage(imFont); + + // Fallback to default raylib texture if font texture loading fails + if (font.texture.id != 0) + { + // Set font texture source rectangle to be used as white texture to draw shapes + // NOTE: It makes possible to draw shapes and text (full UI) in a single draw call + if ((fontWhiteRec.x > 0) && + (fontWhiteRec.y > 0) && + (fontWhiteRec.width > 0) && + (fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec); + } + else font = GetFontDefault(); + + GuiSetFont(font); +#endif + RAYGUI_FREE(imFont.data); + } + } +} + // Load style default over global style void GuiLoadStyleDefault(void) { @@ -4513,7 +5083,7 @@ void GuiLoadStyleDefault(void) GuiSetStyle(DEFAULT, TEXT_SPACING, 1); // DEFAULT, shared by all controls GuiSetStyle(DEFAULT, LINE_COLOR, 0x90abb5ff); // DEFAULT specific property GuiSetStyle(DEFAULT, BACKGROUND_COLOR, 0xf5f5f5ff); // DEFAULT specific property - GuiSetStyle(DEFAULT, TEXT_LINE_SPACING, 5); // DEFAULT, pixels between lines, from bottom of first line to top of second + GuiSetStyle(DEFAULT, TEXT_LINE_SPACING, 12); // DEFAULT, pixels between lines, from bottom of first line to top of second GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); // DEFAULT, text aligned vertically to middle of text-bounds // Initialize control-specific property values @@ -4532,6 +5102,7 @@ void GuiLoadStyleDefault(void) GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); GuiSetStyle(STATUSBAR, TEXT_PADDING, 8); GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(TABBAR, TAB_ITEMS_WIDTH, 160); // Initialize extended property values // NOTE: By default, extended property values are initialized to 0 @@ -4581,6 +5152,9 @@ void GuiLoadStyleDefault(void) // NOTE: Setting up a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering SetShapesTexture(guiFont.texture, RAYGUI_CLITERAL(Rectangle){ whiteChar.x + 1, whiteChar.y + 1, whiteChar.width - 2, whiteChar.height - 2 }); + + // Reset baked icons offset in font + guiIconFontOffsetY = 0; } } @@ -4622,71 +5196,28 @@ const char *GuiIconText(int iconId, const char *text) unsigned int *GuiGetIcons(void) { return guiIconsPtr; } // Load raygui icons file (.rgi) -// NOTE: In case nameIds are required, they can be requested with loadIconsName, -// they are returned as a guiIconsName[iconCount][RAYGUI_ICON_MAX_NAME_LENGTH], // WARNING: guiIconsName[]][] memory should be manually freed! char **GuiLoadIcons(const char *fileName, bool loadIconsName) { - // Style File Structure (.rgi) - // ------------------------------------------------------ - // Offset | Size | Type | Description - // ------------------------------------------------------ - // 0 | 4 | char | Signature: "rGI " - // 4 | 2 | short | Version: 100 - // 6 | 2 | short | reserved - - // 8 | 2 | short | Num icons (N) - // 10 | 2 | short | Icons size (Options: 16, 32, 64) (S) - - // Icons name id (32 bytes per name id) - // foreach (icon) - // { - // 12+32*i | 32 | char | Icon NameId - // } - - // Icons data: One bit per pixel, stored as unsigned int array (depends on icon size) - // S*S pixels/32bit per unsigned int = K unsigned int per icon - // foreach (icon) - // { - // ... | K | unsigned int | Icon Data - // } - FILE *rgiFile = fopen(fileName, "rb"); - char **guiIconsName = NULL; if (rgiFile != NULL) { - char signature[5] = { 0 }; - short version = 0; - short reserved = 0; - short iconCount = 0; - short iconSize = 0; + unsigned char *fileData = NULL; + int dataSize = 0; - fread(signature, 1, 4, rgiFile); - fread(&version, sizeof(short), 1, rgiFile); - fread(&reserved, sizeof(short), 1, rgiFile); - fread(&iconCount, sizeof(short), 1, rgiFile); - fread(&iconSize, sizeof(short), 1, rgiFile); + fseek(rgiFile, 0, SEEK_END); + int size = (int)ftell(rgiFile); + fseek(rgiFile, 0, SEEK_SET); - if ((signature[0] == 'r') && - (signature[1] == 'G') && - (signature[2] == 'I') && - (signature[3] == ' ')) + if (size > 0) { - if (loadIconsName) - { - guiIconsName = (char **)RAYGUI_CALLOC(iconCount, sizeof(char *)); - for (int i = 0; i < iconCount; i++) - { - guiIconsName[i] = (char *)RAYGUI_CALLOC(RAYGUI_ICON_MAX_NAME_LENGTH, sizeof(char)); - fread(guiIconsName[i], 1, RAYGUI_ICON_MAX_NAME_LENGTH, rgiFile); - } - } - else fseek(rgiFile, iconCount*RAYGUI_ICON_MAX_NAME_LENGTH, SEEK_CUR); + fileData = (unsigned char *)RL_CALLOC(size, sizeof(unsigned char)); + // WARNING: File can be partially loaded but ignoring it for simplicity + dataSize = (int)fread(fileData, sizeof(unsigned char), size, rgiFile); - // Read icons data directly over internal icons array - fread(guiIconsPtr, sizeof(unsigned int), (int)iconCount*((int)iconSize*(int)iconSize/32), rgiFile); + guiIconsName = GuiLoadIconsFromMemory(fileData, dataSize, loadIconsName); } fclose(rgiFile); @@ -4696,9 +5227,34 @@ char **GuiLoadIcons(const char *fileName, bool loadIconsName) } // Load icons from memory -// WARNING: Binary files only +// GLOBAL: Updates global variable: guiIconsPtr char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName) { + // Icon File Structure (.rgi) + // ------------------------------------------------------ + // Offset | Size | Type | Description + // ------------------------------------------------------ + // 0 | 4 | char | Signature: "rGI " + // 4 | 2 | short | Version: 100, 500 + // 6 | 2 | short | reserved + + // 8 | 2 | short | Num icons (N) + // 10 | 2 | short | Icons Size (Options: 16, 32, 64) + + // Icons name id (32 bytes per name id) + // foreach (icon) + // { + // 12+32*i | 32 | char | Icon NameId + // } + + // Icons data: One bit per pixel, stored as unsigned int array (depends on icon size) + // Size*Size pixels/32bit per unsigned int = K unsigned int per icon + // foreach (icon) + // { + // ... | K | unsigned int | Icon Data + // } + // ------------------------------------------------------ + unsigned char *fileDataPtr = (unsigned char *)fileData; char **guiIconsName = NULL; @@ -4722,7 +5278,8 @@ char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool { if (loadIconsName) { - guiIconsName = (char **)RAYGUI_CALLOC(iconCount, sizeof(char *)); + // NOTE: Always allocating RAYGUI_ICON_MAX_ICONS names slots + guiIconsName = (char **)RAYGUI_CALLOC(RAYGUI_ICON_MAX_ICONS, sizeof(char *)); for (int i = 0; i < iconCount; i++) { guiIconsName[i] = (char *)RAYGUI_CALLOC(RAYGUI_ICON_MAX_NAME_LENGTH, sizeof(char)); @@ -4748,20 +5305,35 @@ char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool // Draw selected icon using rectangles pixel-by-pixel void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color) { - #define BIT_CHECK(a,b) ((a) & (1u<<(b))) - - for (int i = 0, y = 0; i < RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32; i++) + if ((guiIconFontOffsetY > 0) && (iconId < RAYGUI_ICON_MAX_FONT_BACKED)) { - for (int k = 0; k < 32; k++) - { - if (BIT_CHECK(guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i], k)) - { - #if !defined(RAYGUI_STANDALONE) - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize, (float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color); - #endif - } + int maxIconsPerLine = guiFont.texture.width/(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + int x = iconId%maxIconsPerLine; + int y = iconId/maxIconsPerLine; - if ((k == 15) || (k == 31)) y++; + Rectangle srcRec = { (float)x*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + RAYGUI_ICON_FONT_ATLAS_PADDING, + guiIconFontOffsetY + (float)y*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + RAYGUI_ICON_FONT_ATLAS_PADDING, + RAYGUI_ICON_SIZE, RAYGUI_ICON_SIZE }; + Rectangle dstRec = { (float)posX, (float)posY, (float)pixelSize*RAYGUI_ICON_SIZE, (float)pixelSize*RAYGUI_ICON_SIZE }; + + DrawTexturePro(guiFont.texture, srcRec, dstRec, RAYGUI_CLITERAL(Vector2){ 0, 0 }, 0.0f, color); + } + else + { + #define BIT_CHECK(a,b) ((a) & (1u<<(b))) + + for (int i = 0, y = 0; i < RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32; i++) + { + for (int k = 0; k < 32; k++) + { + if (BIT_CHECK(guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i], k)) + { + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize, + (float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color); + } + + if ((k == 15) || (k == 31)) y++; + } } } } @@ -4772,28 +5344,56 @@ void GuiSetIconScale(int scale) if (scale >= 1) guiIconScale = scale; } -// Get text width considering gui style and icon size (if required) +// Get text width considering gui style and icon size (if required). +// For multi-line text (containing '\n'), returns the width of the widest line. int GuiGetTextWidth(const char *text) { - #if !defined(ICON_TEXT_PADDING) - #define ICON_TEXT_PADDING 4 - #endif + if (text == NULL) return 0; + + int maxWidth = 0; + const char *linePtr = text; + + while ((linePtr[0] != '\0') && ((linePtr - text) < MAX_LINE_BUFFER_SIZE)) + { + int lineWidth = GetLineWidth(linePtr); + if (lineWidth > maxWidth) maxWidth = lineWidth; + + // Skip to the next '\n' (or end of string/buffer) + while ((linePtr[0] != '\0') && (linePtr[0] != '\n') && ((linePtr - text) < MAX_LINE_BUFFER_SIZE)) + { + linePtr++; + } + // Advance past the '\n' delimiter to the start of the next line + if (linePtr[0] == '\n') linePtr++; + } + + return maxWidth; +} + +#endif // !RAYGUI_NO_ICONS + +//---------------------------------------------------------------------------------- +// Module Internal Functions Definition +//---------------------------------------------------------------------------------- +// Get text line width (stops at '\n' or '\0') +// NOTE: Considers icon marker '#NNN#' +static int GetLineWidth(const char *text) +{ +#if !defined(RAYGUI_ICON_TEXT_PADDING) + #define RAYGUI_ICON_TEXT_PADDING 4 +#endif Vector2 textSize = { 0 }; int textIconOffset = 0; if ((text != NULL) && (text[0] != '\0')) { + // Icon marker: '#' + 1..3 digits + '#' (matches GetTextIcon()) if (text[0] == '#') { - for (int i = 1; (i < 5) && (text[i] != '\0'); i++) - { - if (text[i] == '#') - { - textIconOffset = i; - break; - } - } + int pos = 1; + while ((pos < 4) && (text[pos] >= '0') && (text[pos] <= '9')) pos++; + if (text[pos] == '#') textIconOffset = pos + 1; } text += textIconOffset; @@ -4801,10 +5401,10 @@ int GuiGetTextWidth(const char *text) // Make sure guiFont is set, GuiGetStyle() initializes it lazynessly float fontSize = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - // Custom MeasureText() implementation + // Custom MeasureText() implementation -- single line only if ((guiFont.texture.id > 0) && (text != NULL)) { - // Get size in bytes of text, considering end of line and line break + // Get size in bytes of the line, considering end of line and line break int size = 0; for (int i = 0; i < MAX_LINE_BUFFER_SIZE; i++) { @@ -4828,239 +5428,12 @@ int GuiGetTextWidth(const char *text) } } - if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + ICON_TEXT_PADDING); + if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + RAYGUI_ICON_TEXT_PADDING); } return (int)textSize.x; } -#endif // !RAYGUI_NO_ICONS - -//---------------------------------------------------------------------------------- -// Module Internal Functions Definition -//---------------------------------------------------------------------------------- -// Load style from memory -// WARNING: Binary files only -static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize) -{ - unsigned char *fileDataPtr = (unsigned char *)fileData; - - char signature[5] = { 0 }; - short version = 0; - short reserved = 0; - int propertyCount = 0; - - memcpy(signature, fileDataPtr, 4); - memcpy(&version, fileDataPtr + 4, sizeof(short)); - memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short)); - memcpy(&propertyCount, fileDataPtr + 4 + 2 + 2, sizeof(int)); - fileDataPtr += 12; - - if ((signature[0] == 'r') && - (signature[1] == 'G') && - (signature[2] == 'S') && - (signature[3] == ' ')) - { - short controlId = 0; - short propertyId = 0; - unsigned int propertyValue = 0; - - for (int i = 0; i < propertyCount; i++) - { - memcpy(&controlId, fileDataPtr, sizeof(short)); - memcpy(&propertyId, fileDataPtr + 2, sizeof(short)); - memcpy(&propertyValue, fileDataPtr + 2 + 2, sizeof(unsigned int)); - fileDataPtr += 8; - - if (controlId == 0) // DEFAULT control - { - // If a DEFAULT property is loaded, it is propagated to all controls - // NOTE: All DEFAULT properties should be defined first in the file - GuiSetStyle(0, (int)propertyId, propertyValue); - - if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int j = 1; j < RAYGUI_MAX_CONTROLS; j++) GuiSetStyle(j, (int)propertyId, propertyValue); - } - else GuiSetStyle((int)controlId, (int)propertyId, propertyValue); - } - - // Font loading is highly dependant on raylib API to load font data and image - -#if !defined(RAYGUI_STANDALONE) - // Load custom font if available - int fontDataSize = 0; - memcpy(&fontDataSize, fileDataPtr, sizeof(int)); - fileDataPtr += 4; - - if (fontDataSize > 0) - { - Font font = { 0 }; - int fontType = 0; // 0-Normal, 1-SDF - - memcpy(&font.baseSize, fileDataPtr, sizeof(int)); - memcpy(&font.glyphCount, fileDataPtr + 4, sizeof(int)); - memcpy(&fontType, fileDataPtr + 4 + 4, sizeof(int)); - fileDataPtr += 12; - - // Load font white rectangle - Rectangle fontWhiteRec = { 0 }; - memcpy(&fontWhiteRec, fileDataPtr, sizeof(Rectangle)); - fileDataPtr += 16; - - // Load font image parameters - int fontImageUncompSize = 0; - int fontImageCompSize = 0; - memcpy(&fontImageUncompSize, fileDataPtr, sizeof(int)); - memcpy(&fontImageCompSize, fileDataPtr + 4, sizeof(int)); - fileDataPtr += 8; - - Image imFont = { 0 }; - imFont.mipmaps = 1; - memcpy(&imFont.width, fileDataPtr, sizeof(int)); - memcpy(&imFont.height, fileDataPtr + 4, sizeof(int)); - memcpy(&imFont.format, fileDataPtr + 4 + 4, sizeof(int)); - fileDataPtr += 12; - - if ((fontImageCompSize > 0) && (fontImageCompSize != fontImageUncompSize)) - { - // Compressed font atlas image data (DEFLATE), it requires DecompressData() - int dataUncompSize = 0; - unsigned char *compData = (unsigned char *)RAYGUI_CALLOC(fontImageCompSize, sizeof(unsigned char)); - memcpy(compData, fileDataPtr, fontImageCompSize); - fileDataPtr += fontImageCompSize; - - imFont.data = DecompressData(compData, fontImageCompSize, &dataUncompSize); - - // Security check, dataUncompSize must match the provided fontImageUncompSize - if (dataUncompSize != fontImageUncompSize) RAYGUI_LOG("WARNING: Uncompressed font atlas image data could be corrupted"); - - RAYGUI_FREE(compData); - } - else - { - // Font atlas image data is not compressed - imFont.data = (unsigned char *)RAYGUI_CALLOC(fontImageUncompSize, sizeof(unsigned char)); - memcpy(imFont.data, fileDataPtr, fontImageUncompSize); - fileDataPtr += fontImageUncompSize; - } - - if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture); - font.texture = LoadTextureFromImage(imFont); - - RAYGUI_FREE(imFont.data); - - // Validate font atlas texture was loaded correctly - if (font.texture.id != 0) - { - // Load font recs data - int recsDataSize = font.glyphCount*sizeof(Rectangle); - int recsDataCompressedSize = 0; - - // WARNING: Version 400 adds the compression size parameter - if (version >= 400) - { - // RGS files version 400 support compressed recs data - memcpy(&recsDataCompressedSize, fileDataPtr, sizeof(int)); - fileDataPtr += sizeof(int); - } - - if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize)) - { - // Recs data is compressed, uncompress it - unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_CALLOC(recsDataCompressedSize, sizeof(unsigned char)); - - memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize); - fileDataPtr += recsDataCompressedSize; - - int recsDataUncompSize = 0; - font.recs = (Rectangle *)DecompressData(recsDataCompressed, recsDataCompressedSize, &recsDataUncompSize); - - // Security check, data uncompressed size must match the expected original data size - if (recsDataUncompSize != recsDataSize) RAYGUI_LOG("WARNING: Uncompressed font recs data could be corrupted"); - - RAYGUI_FREE(recsDataCompressed); - } - else - { - // Recs data is uncompressed - font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle)); - for (int i = 0; i < font.glyphCount; i++) - { - memcpy(&font.recs[i], fileDataPtr, sizeof(Rectangle)); - fileDataPtr += sizeof(Rectangle); - } - } - - // Load font glyphs info data - int glyphsDataSize = font.glyphCount*16; // 16 bytes data per glyph - int glyphsDataCompressedSize = 0; - - // WARNING: Version 400 adds the compression size parameter - if (version >= 400) - { - // RGS files version 400 support compressed glyphs data - memcpy(&glyphsDataCompressedSize, fileDataPtr, sizeof(int)); - fileDataPtr += sizeof(int); - } - - // Allocate required glyphs space to fill with data - font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo)); - - if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize)) - { - // Glyphs data is compressed, uncompress it - unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_CALLOC(glyphsDataCompressedSize, sizeof(unsigned char)); - - memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize); - fileDataPtr += glyphsDataCompressedSize; - - int glyphsDataUncompSize = 0; - unsigned char *glyphsDataUncomp = DecompressData(glypsDataCompressed, glyphsDataCompressedSize, &glyphsDataUncompSize); - - // Security check, data uncompressed size must match the expected original data size - if (glyphsDataUncompSize != glyphsDataSize) RAYGUI_LOG("WARNING: Uncompressed font glyphs data could be corrupted"); - - unsigned char *glyphsDataUncompPtr = glyphsDataUncomp; - - for (int i = 0; i < font.glyphCount; i++) - { - memcpy(&font.glyphs[i].value, glyphsDataUncompPtr, sizeof(int)); - memcpy(&font.glyphs[i].offsetX, glyphsDataUncompPtr + 4, sizeof(int)); - memcpy(&font.glyphs[i].offsetY, glyphsDataUncompPtr + 8, sizeof(int)); - memcpy(&font.glyphs[i].advanceX, glyphsDataUncompPtr + 12, sizeof(int)); - glyphsDataUncompPtr += 16; - } - - RAYGUI_FREE(glypsDataCompressed); - RAYGUI_FREE(glyphsDataUncomp); - } - else - { - // Glyphs data is uncompressed - for (int i = 0; i < font.glyphCount; i++) - { - memcpy(&font.glyphs[i].value, fileDataPtr, sizeof(int)); - memcpy(&font.glyphs[i].offsetX, fileDataPtr + 4, sizeof(int)); - memcpy(&font.glyphs[i].offsetY, fileDataPtr + 8, sizeof(int)); - memcpy(&font.glyphs[i].advanceX, fileDataPtr + 12, sizeof(int)); - fileDataPtr += 16; - } - } - } - else font = GetFontDefault(); // Fallback in case of errors loading font atlas texture - - GuiSetFont(font); - - // Set font texture source rectangle to be used as white texture to draw shapes - // NOTE: It makes possible to draw shapes and text (full UI) in a single draw call - if ((fontWhiteRec.x > 0) && - (fontWhiteRec.y > 0) && - (fontWhiteRec.width > 0) && - (fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec); - } -#endif - } -} - // Get text bounds considering control bounds static Rectangle GetTextBounds(int control, Rectangle bounds) { @@ -5081,11 +5454,11 @@ static Rectangle GetTextBounds(int control, Rectangle bounds) case SLIDER: case CHECKBOX: case VALUEBOX: - case CONTROL11: - // TODO: More special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER + case TABBAR: + // TODO: Special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER default: { - // TODO: WARNING: TEXT_ALIGNMENT is already considered in GuiDrawText() + // WARNING: TEXT_ALIGNMENT is already considered in GuiDrawText() if (GuiGetStyle(control, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT) textBounds.x -= GuiGetStyle(control, TEXT_PADDING); else textBounds.x += GuiGetStyle(control, TEXT_PADDING); } @@ -5096,12 +5469,12 @@ static Rectangle GetTextBounds(int control, Rectangle bounds) } // Get text icon if provided and move text cursor -// NOTE: Up to #999# values supported for iconId +// NOTE: Up to RAYGUI_ICON_MAX_ICONS supported for iconId static const char *GetTextIcon(const char *text, int *iconId) { #if !defined(RAYGUI_NO_ICONS) *iconId = -1; - if (text[0] == '#') // Maybe it is stars with an icon, ending # must be found + if (text[0] == '#') // Maybe an icon, if it starts with # but an ending # must be found { char iconValue[4] = { 0 }; // Maximum length for icon value: 3 digits + '\0' @@ -5114,11 +5487,15 @@ static const char *GetTextIcon(const char *text, int *iconId) if (text[pos] == '#') { - *iconId = TextToInteger(iconValue); + int rawIconId = TextToInteger(iconValue); + if (rawIconId < RAYGUI_ICON_MAX_ICONS) + { + *iconId = rawIconId; - // Move text pointer after icon - // WARNING: If only icon provided, it could point to EOL character: '\0' - if (*iconId >= 0) text += (pos + 1); + // Move text pointer after icon + // WARNING: If only icon provided, it could point to EOL character: '\0' + if (*iconId >= 0) text += (pos + 1); + } } } #endif @@ -5186,8 +5563,8 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C { #define TEXT_VALIGN_PIXEL_OFFSET(h) ((int)h%2) // Vertical alignment for pixel perfect - #if !defined(ICON_TEXT_PADDING) - #define ICON_TEXT_PADDING 4 + #if !defined(RAYGUI_ICON_TEXT_PADDING) + #define RAYGUI_ICON_TEXT_PADDING 4 #endif if ((text == NULL) || (text[0] == '\0')) return; // Security check @@ -5223,9 +5600,9 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C Vector2 textBoundsPosition = { textBounds.x, textBounds.y }; float textBoundsWidthOffset = 0.0f; - // NOTE: Get text size after icon has been processed - // WARNING: GuiGetTextWidth() also processes text icon to get width! -> Really needed? - int textSizeX = GuiGetTextWidth(lines[i]); + // NOTE: Icon was already stripped above by GetTextIcon(); GetLineWidth() + // takes no icon path here and returns only the glyph width of this line. + int textSizeX = GetLineWidth(lines[i]); // If text requires an icon, add size to measure if (iconId >= 0) @@ -5234,7 +5611,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C // WARNING: If only icon provided, text could be pointing to EOF character: '\0' #if !defined(RAYGUI_NO_ICONS) - if ((lines[i] != NULL) && (lines[i][0] != '\0')) textSizeX += ICON_TEXT_PADDING; + if ((lines[i] != NULL) && (lines[i][0] != '\0')) textSizeX += RAYGUI_ICON_TEXT_PADDING; #endif } @@ -5271,12 +5648,11 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C { // NOTE: Considering icon height, probably different than text size GuiDrawIcon(iconId, (int)textBoundsPosition.x, (int)(textBounds.y + textBounds.height/2 - RAYGUI_ICON_SIZE*guiIconScale/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height)), guiIconScale, tint); - textBoundsPosition.x += (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); - textBoundsWidthOffset = (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); + textBoundsPosition.x += (float)(RAYGUI_ICON_SIZE*guiIconScale + RAYGUI_ICON_TEXT_PADDING); + textBoundsWidthOffset = (float)(RAYGUI_ICON_SIZE*guiIconScale + RAYGUI_ICON_TEXT_PADDING); } #endif - // Get size in bytes of text, - // considering end of line and line break + // Get size in bytes of text, considering end of line and line break int lineSize = 0; for (int c = 0; (lines[i][c] != '\0') && (lines[i][c] != '\n') && (lines[i][c] != '\r'); c++, lineSize++){ } float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize; @@ -5297,7 +5673,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C // NOTE: Normally, exiting the decoding sequence as soon as a bad byte is found (and return 0x3f) // but all of the bad bytes need to be drawn using the '?' symbol, moving one byte - if (codepoint == 0x3f) codepointSize = 1; // TODO: Review not recognized codepoints size + if (codepoint == 0x3f) codepointSize = 1; // WARNING: Not recognized codepoints size // Get glyph width to check if it goes out of bounds if (guiFont.glyphs[index].advanceX == 0) glyphWidth = ((float)guiFont.recs[index].width*scaleFactor); @@ -5313,7 +5689,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C textOffsetX = 0.0f; textOffsetY += (GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); - if (tempWrapCharMode) // Wrap at char level when too long words + if (tempWrapCharMode) // Wrap at char level when too long words { wrapMode = TEXT_WRAP_WORD; tempWrapCharMode = false; @@ -5344,12 +5720,12 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C } } - if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint + if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint else { - // TODO: There are multiple types of spaces in Unicode, + // WARNING: There are multiple types of spaces in Unicode, // maybe it's a good idea to add support for more: http://jkorpela.fi/chars/spaces.html - if ((codepoint != ' ') && (codepoint != '\t')) // Do not draw codepoints with no glyph + if ((codepoint != ' ') && (codepoint != '\t')) // Do not draw codepoints with no glyph { if (wrapMode == TEXT_WRAP_NONE) { @@ -5391,7 +5767,8 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C } if (wrapMode == TEXT_WRAP_NONE) posOffsetY += (float)(GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); - else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) posOffsetY += (textOffsetY + (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); + else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) + posOffsetY += (textOffsetY + GuiGetStyle(DEFAULT, TEXT_SIZE)); //--------------------------------------------------------------------------------- } @@ -5428,7 +5805,8 @@ static void GuiTooltip(Rectangle controlRec) { if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiControlExclusiveMode) { - Vector2 textSize = MeasureTextEx(GuiGetFont(), guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + Vector2 textSize = MeasureTextEx(guiFont, guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); if ((controlRec.x + textSize.x + 16) > GetScreenWidth()) controlRec.x -= (textSize.x + 16 - controlRec.width); @@ -5450,9 +5828,264 @@ static void GuiTooltip(Rectangle controlRec) } } +// Scroll bar control (used by GuiScrollPanel()) +static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) +{ + GuiState state = guiState; + + // Is the scrollbar horizontal or vertical? + bool isVertical = (bounds.width > bounds.height)? false : true; + + // The size (width or height depending on scrollbar type) of the spinner buttons + const int spinnerSize = GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)? + (isVertical? (int)bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) : + (int)bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0; + + // Arrow buttons [<] [>] [∧] [∨] + Rectangle arrowUpLeft = { 0 }; + Rectangle arrowDownRight = { 0 }; + + // Actual area of the scrollbar excluding the arrow buttons + Rectangle scrollbar = { 0 }; + + // Slider bar that moves --[///]----- + Rectangle slider = { 0 }; + + // Normalize value + if (value > maxValue) value = maxValue; + if (value < minValue) value = minValue; + + int valueRange = maxValue - minValue; + if (valueRange <= 0) valueRange = 1; + + int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); + if (sliderSize < 1) sliderSize = 1; // Consider a minimum slider size of 1 pixel + + // Calculate rectangles for all of the components + arrowUpLeft = RAYGUI_CLITERAL(Rectangle){ + (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), + (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), + (float)spinnerSize, (float)spinnerSize }; + + if (isVertical) + { + arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + bounds.height - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; + scrollbar = RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), arrowUpLeft.y + arrowUpLeft.height, bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)), bounds.height - arrowUpLeft.height - arrowDownRight.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) }; + + // Make sure the slider won't get outside of the scrollbar + sliderSize = (sliderSize >= scrollbar.height)? ((int)scrollbar.height - 2) : sliderSize; + slider = RAYGUI_CLITERAL(Rectangle){ + bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), + scrollbar.y + (int)(((float)(value - minValue)/valueRange)*(scrollbar.height - sliderSize)), + bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)), + (float)sliderSize }; + } + else // horizontal + { + arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; + scrollbar = RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x + arrowUpLeft.width, bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), bounds.width - arrowUpLeft.width - arrowDownRight.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)) }; + + // Make sure the slider won't get outside of the scrollbar + sliderSize = (sliderSize >= scrollbar.width)? ((int)scrollbar.width - 2) : sliderSize; + slider = RAYGUI_CLITERAL(Rectangle){ + scrollbar.x + (int)(((float)(value - minValue)/valueRange)*(scrollbar.width - sliderSize)), + bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), + (float)sliderSize, + bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)) }; + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (GUI_BUTTON_DOWN && + !CheckCollisionPointRec(mousePoint, arrowUpLeft) && + !CheckCollisionPointRec(mousePoint, arrowDownRight)) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + state = STATE_PRESSED; + + if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); + else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + + // Handle mouse wheel + float scrollDelta = GUI_SCROLL_DELTA; + if (scrollDelta != 0) value += (int)scrollDelta; + + // Handle mouse button down + if (GUI_BUTTON_PRESSED) + { + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + + // Check arrows click + if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + else if (!CheckCollisionPointRec(mousePoint, slider)) + { + // If click on scrollbar position but not on slider, place slider directly on that position + if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); + else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); + } + + state = STATE_PRESSED; + } + + // Keyboard control on mouse hover scrollbar + /* + if (isVertical) + { + if (GUI_KEY_DOWN(KEY_DOWN)) value += 5; + else if (GUI_KEY_DOWN(KEY_UP)) value -= 5; + } + else + { + if (GUI_KEY_DOWN(KEY_RIGHT)) value += 5; + else if (GUI_KEY_DOWN(KEY_LEFT)) value -= 5; + } + */ + } + + // Normalize value + if (value > maxValue) value = maxValue; + if (value < minValue) value = minValue; + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED))); // Draw the background + + GuiDrawRectangle(scrollbar, 0, BLANK, GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL))); // Draw the scrollbar active area background + GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BORDER + state*3))); // Draw the slider bar + + // Draw arrows (using icon if available) + if (GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)) + { +#if defined(RAYGUI_NO_ICONS) + GuiDrawText(isVertical? "^" : "<", + RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); + GuiDrawText(isVertical? "v" : ">", + RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); +#else + GuiDrawText(isVertical? GuiIconText(ICON_ARROW_UP_FILL, NULL) : GuiIconText(ICON_ARROW_LEFT_FILL, NULL), + RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_UP_FILL / ICON_ARROW_LEFT_FILL + GuiDrawText(isVertical? GuiIconText(ICON_ARROW_DOWN_FILL, NULL) : GuiIconText(ICON_ARROW_RIGHT_FILL, NULL), + RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_DOWN_FILL / ICON_ARROW_RIGHT_FILL +#endif + } + //-------------------------------------------------------------------- + + return value; +} + +// Update font image atlas to append raygui icons +static int GuiFontIconBaking(Image *imFont, Font font, Rectangle *whiteRec) +{ + int iconOffsetY = 0; + + // Check max glyph rec y bottom position in the atlas image, + // to start drawing icons below that line + int maxGlyphRecY = 0; + for (int i = 0; i < font.glyphCount; i++) + { + if ((font.recs[i].y + font.recs[i].height) > maxGlyphRecY) + maxGlyphRecY = (int)font.recs[i].y + (int)font.recs[i].height; + } + + int maxIconsPerLine = imFont->width/(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + int reqIconLines = RAYGUI_ICON_MAX_FONT_BACKED/maxIconsPerLine + RAYGUI_ICON_MAX_FONT_BACKED%maxIconsPerLine + 1; // One extra line + int reqHeight = reqIconLines*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + + // Check if image requires scaling and how much + if ((maxGlyphRecY + reqHeight) > imFont->height) + { + int newImHeight = 1; + while (newImHeight < (maxGlyphRecY + reqHeight)) newImHeight <<= 1; // Round to next POT + + char *newImData = (char *)RL_CALLOC(imFont->width*newImHeight*2, sizeof(char)); + memcpy(newImData, imFont->data, imFont->width*imFont->height*2); + RL_FREE(imFont->data); + + // Clear imFont bottom-right corner rec + for (int y = 0; y < 4; y++) + for (int x = 0; x < 4; x++) + ((unsigned short *)newImData)[(imFont->height - y - 1)*imFont->width + imFont->width - x - 1] = 0x0000; + + imFont->data = newImData; + imFont->height = newImHeight; + + // Set new image white corner and new white rec + for (int y = 0; y < 3; y++) + for (int x = 0; x < 3; x++) + ((unsigned short *)newImData)[(imFont->height - y - 1)*imFont->width + imFont->width - x - 1] = 0xffff; + + *whiteRec = RAYGUI_CLITERAL(Rectangle){ (float)imFont->width - 2, (float)imFont->height - 2, 1, 1 }; + } + + // Calculate image offset positions to start drawing + // NOTE: For Y, look for a multiple of icon size + 2*padding, for better alignment + int offsetX = RAYGUI_ICON_FONT_ATLAS_PADDING; + int offsetY = ((maxGlyphRecY + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING - 1))/ + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING))*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + + RAYGUI_ICON_FONT_ATLAS_PADDING; + + iconOffsetY = offsetY - RAYGUI_ICON_FONT_ATLAS_PADDING; + unsigned short *pixels = (unsigned short *)imFont->data; + + #define BIT_CHECK(a,b) ((a) & (1u<<(b))) + + for (int iconId = 0; iconId < RAYGUI_ICON_MAX_FONT_BACKED; iconId++) + { + // Wrap to next line if next icon won't fit + if ((offsetX + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING)) > imFont->width) + { + offsetX = RAYGUI_ICON_FONT_ATLAS_PADDING; + offsetY += RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING; + } + + for (int i = 0, y = 0; i < RAYGUI_ICON_DATA_ELEMENTS; i++) + { + unsigned int data = guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i]; + + for (int k = 0; k < 32; k++) + { + pixels[(offsetY + y)*imFont->width + offsetX + k%16] = (BIT_CHECK(data, k))? 0xffff : 0x00ff; + + if ((k == 15) || (k == 31)) y++; + } + } + + // Update current icon X position + offsetX += (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + } + + return iconOffsetY; +} + // Split controls text into multiple strings -// Also check for multiple columns (required by GuiToggleGroup()) -static char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow) +// NOTE: Re-used by GuiToggleSlider(), GuiComboBox(), GuiDropdownBox(), GuiListView(), GuiMessageBox(), GuiInputBox() +static char **GuiTextSplit(const char *text, char delimiter, int *count) { // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, @@ -5461,24 +6094,19 @@ static char **GuiTextSplit(const char *text, char delimiter, int *count, int *te // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE // NOTE: Those definitions could be externally provided if required - // TODO: HACK: GuiTextSplit() - Review how textRows are returned to user - // textRow is an externally provided array of integers that stores row number for every splitted string - #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS) #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128 #endif #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE) - #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 + #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 // WARNING: Max expected size for all concat items #endif - static char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL }; // String pointers array (points to buffer data) + static char *itemPtrs[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { 0 }; // String pointers array (points to buffer data) static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; // Buffer data (text input copy with '\0' added) memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE); - result[0] = buffer; - int counter = 1; - - if (textRow != NULL) textRow[0] = 0; + itemPtrs[0] = buffer; + int itemCounter = 1; // Count how many substrings text contains and point to every one of them for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++) @@ -5487,24 +6115,16 @@ static char **GuiTextSplit(const char *text, char delimiter, int *count, int *te if (buffer[i] == '\0') break; else if ((buffer[i] == delimiter) || (buffer[i] == '\n')) { - result[counter] = buffer + i + 1; + itemPtrs[itemCounter] = buffer + i + 1; + buffer[i] = '\0'; // Set terminator for current item - if (textRow != NULL) - { - if (buffer[i] == '\n') textRow[counter] = textRow[counter - 1] + 1; - else textRow[counter] = textRow[counter - 1]; - } - - buffer[i] = '\0'; // Set an end of string at this point - - counter++; - if (counter >= RAYGUI_TEXTSPLIT_MAX_ITEMS) break; + itemCounter++; + if (itemCounter >= RAYGUI_TEXTSPLIT_MAX_ITEMS) break; } } - *count = counter; - - return result; + *count = itemCounter; + return itemPtrs; } // Convert color data from RGB to HSV @@ -5631,179 +6251,9 @@ static Vector3 ConvertHSVtoRGB(Vector3 hsv) return rgb; } -// Scroll bar control (used by GuiScrollPanel()) -static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) -{ - GuiState state = guiState; - - // Is the scrollbar horizontal or vertical? - bool isVertical = (bounds.width > bounds.height)? false : true; - - // The size (width or height depending on scrollbar type) of the spinner buttons - const int spinnerSize = GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)? - (isVertical? (int)bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) : - (int)bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0; - - // Arrow buttons [<] [>] [∧] [∨] - Rectangle arrowUpLeft = { 0 }; - Rectangle arrowDownRight = { 0 }; - - // Actual area of the scrollbar excluding the arrow buttons - Rectangle scrollbar = { 0 }; - - // Slider bar that moves --[///]----- - Rectangle slider = { 0 }; - - // Normalize value - if (value > maxValue) value = maxValue; - if (value < minValue) value = minValue; - - int valueRange = maxValue - minValue; - if (valueRange <= 0) valueRange = 1; - - int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); - if (sliderSize < 1) sliderSize = 1; // TODO: Consider a minimum slider size - - // Calculate rectangles for all of the components - arrowUpLeft = RAYGUI_CLITERAL(Rectangle){ - (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), - (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), - (float)spinnerSize, (float)spinnerSize }; - - if (isVertical) - { - arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + bounds.height - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; - scrollbar = RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), arrowUpLeft.y + arrowUpLeft.height, bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)), bounds.height - arrowUpLeft.height - arrowDownRight.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) }; - - // Make sure the slider won't get outside of the scrollbar - sliderSize = (sliderSize >= scrollbar.height)? ((int)scrollbar.height - 2) : sliderSize; - slider = RAYGUI_CLITERAL(Rectangle){ - bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), - scrollbar.y + (int)(((float)(value - minValue)/valueRange)*(scrollbar.height - sliderSize)), - bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)), - (float)sliderSize }; - } - else // horizontal - { - arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; - scrollbar = RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x + arrowUpLeft.width, bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), bounds.width - arrowUpLeft.width - arrowDownRight.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)) }; - - // Make sure the slider won't get outside of the scrollbar - sliderSize = (sliderSize >= scrollbar.width)? ((int)scrollbar.width - 2) : sliderSize; - slider = RAYGUI_CLITERAL(Rectangle){ - scrollbar.x + (int)(((float)(value - minValue)/valueRange)*(scrollbar.width - sliderSize)), - bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), - (float)sliderSize, - bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)) }; - } - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GUI_POINTER_POSITION; - - if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds - { - if (GUI_BUTTON_DOWN && - !CheckCollisionPointRec(mousePoint, arrowUpLeft) && - !CheckCollisionPointRec(mousePoint, arrowDownRight)) - { - if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) - { - state = STATE_PRESSED; - - if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); - else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); - } - } - else - { - guiControlExclusiveMode = false; - guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; - } - } - else if (CheckCollisionPointRec(mousePoint, bounds)) - { - state = STATE_FOCUSED; - - // Handle mouse wheel - float scrollDelta = GUI_SCROLL_DELTA; - if (scrollDelta != 0) value += (int)scrollDelta; - - // Handle mouse button down - if (GUI_BUTTON_PRESSED) - { - guiControlExclusiveMode = true; - guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts - - // Check arrows click - if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - else if (!CheckCollisionPointRec(mousePoint, slider)) - { - // If click on scrollbar position but not on slider, place slider directly on that position - if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); - else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); - } - - state = STATE_PRESSED; - } - - // Keyboard control on mouse hover scrollbar - /* - if (isVertical) - { - if (GUI_KEY_DOWN(KEY_DOWN)) value += 5; - else if (GUI_KEY_DOWN(KEY_UP)) value -= 5; - } - else - { - if (GUI_KEY_DOWN(KEY_RIGHT)) value += 5; - else if (GUI_KEY_DOWN(KEY_LEFT)) value -= 5; - } - */ - } - - // Normalize value - if (value > maxValue) value = maxValue; - if (value < minValue) value = minValue; - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED))); // Draw the background - - GuiDrawRectangle(scrollbar, 0, BLANK, GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL))); // Draw the scrollbar active area background - GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BORDER + state*3))); // Draw the slider bar - - // Draw arrows (using icon if available) - if (GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)) - { -#if defined(RAYGUI_NO_ICONS) - GuiDrawText(isVertical? "^" : "<", - RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); - GuiDrawText(isVertical? "v" : ">", - RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); -#else - GuiDrawText(isVertical? "#121#" : "#118#", - RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_UP_FILL / ICON_ARROW_LEFT_FILL - GuiDrawText(isVertical? "#120#" : "#119#", - RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_DOWN_FILL / ICON_ARROW_RIGHT_FILL -#endif - } - //-------------------------------------------------------------------- - - return value; -} - // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f -// WARNING: It multiplies current alpha by alpha scale factor +// WARNING: It multiplies current alpha by alpha scale factor, +// raylib Fade() multiplies alpha by 255.0f static Color GuiFade(Color color, float alpha) { if (alpha < 0.0f) alpha = 0.0f; @@ -5828,6 +6278,19 @@ static Color GetColor(int hexValue) return color; } +// Get color with alpha applied, alpha goes from 0.0f to 1.0f +static Color Fade(Color color, float alpha) +{ + Color result = color; + + if (alpha < 0.0f) alpha = 0.0f; + else if (alpha > 1.0f) alpha = 1.0f; + + result.a = (unsigned char)(255.0f*alpha); + + return result; +} + // Returns hexadecimal value for a Color static int ColorToInt(Color color) { @@ -5852,7 +6315,8 @@ static const char *TextFormat(const char *text, ...) #define RAYGUI_TEXTFORMAT_MAX_SIZE 256 #endif - static char buffer[RAYGUI_TEXTFORMAT_MAX_SIZE]; + static char buffer[RAYGUI_TEXTFORMAT_MAX_SIZE] = { 0 }; + memset(buffer, 0, RAYGUI_TEXTFORMAT_MAX_SIZE); va_list args; va_start(args, text); @@ -5862,61 +6326,6 @@ static const char *TextFormat(const char *text, ...) return buffer; } -// Draw rectangle with vertical gradient fill color -// NOTE: This function is only used by GuiColorPicker() -static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2) -{ - Rectangle bounds = { (float)posX, (float)posY, (float)width, (float)height }; - DrawRectangleGradientEx(bounds, color1, color2, color2, color1); -} - -// Split string into multiple strings -char **TextSplit(const char *text, char delimiter, int *count) -{ - // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) - // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, - // all used memory is static... it has some limitations: - // 1. Maximum number of possible split strings is set by RAYGUI_TEXTSPLIT_MAX_ITEMS - // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE - - #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS) - #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128 - #endif - #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE) - #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 - #endif - - static const char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL }; - static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; - memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE); - - result[0] = buffer; - int counter = 0; - - if (text != NULL) - { - counter = 1; - - // Count how many substrings text contains and point to every one of them - for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++) - { - buffer[i] = text[i]; - if (buffer[i] == '\0') break; - else if (buffer[i] == delimiter) - { - buffer[i] = '\0'; // Set an end of string at this point - result[counter] = buffer + i + 1; - counter++; - - if (counter == RAYGUI_TEXTSPLIT_MAX_ITEMS) break; - } - } - } - - *count = counter; - return result; -} - // Get integer value from text // NOTE: This function replaces atoi() [stdlib.h] static int TextToInteger(const char *text) diff --git a/examples/core/raygui.h b/examples/core/raygui.h index 03e487912..f7a116150 100644 --- a/examples/core/raygui.h +++ b/examples/core/raygui.h @@ -1,6 +1,6 @@ /******************************************************************************************* * -* raygui v5.0-dev - A simple and easy-to-use immediate-mode gui library +* raygui v5.0 - A simple and easy-to-use immediate-mode gui library * * DESCRIPTION: * raygui is a tools-dev-focused immediate-mode-gui library based on raylib but also @@ -37,7 +37,7 @@ * - Line * - Panel --> StatusBar * - ScrollPanel --> StatusBar -* - TabBar --> Button +* - TabBar --> Toggle, Button * * # Basic Controls * - Label @@ -134,6 +134,10 @@ * Includes custom ricons.h header defining a set of custom icons, * this file can be generated using rGuiIcons tool * +* #define RAYGUI_FONT_ICONS_BAKING +* On gui font loading from style file, append the icons to font atlas image, so, +* icons can be drawn along the text as a texture, instead of using shapes to draw them +* * #define RAYGUI_DEBUG_RECS_BOUNDS * Draw control bounds rectangles for debug * @@ -141,16 +145,26 @@ * Draw text bounds rectangles for debug * * VERSIONS HISTORY: -* 5.0 (xx-Mar-2026) ADDED: Support up to 32 controls (v500) +* 5.0 (20-Jul-2026) ADDED: NEW control: GuiTabBar() +* ADDED: Support up to 512 icons (v500) +* ADDED: Support icons baking into font atlas image * ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes -* ADDED: GuiValueBoxFloat() +* ADDED: GuiValueBoxFloat(), with floats support * ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP * ADDED: GuiListView() property: LIST_ITEMS_BORDER_WIDTH -* ADDED: GuiLoadIconsFromMemory() -* ADDED: Multiple new icons +* ADDED: GuiLoadIconsFromMemory(), used by GuiLoadIcons() * ADDED: Macros for inputs customization, raylib decoupling +* ADDED: Control result return values: 1-RESULT_PRESSED, 2-RESULT_CHANGED, >2-Control_custom * REMOVED: GuiSpinner() from controls list, using BUTTON + VALUEBOX properties * REMOVED: GuiSliderPro(), functionality was redundant +* REMOVED: TextSplit() raylib function requirement on RAYGUI_STANDALONE +* REDESIGNED: WARNING: GuiLoadStyleFromMemory() to support icons baking into font atlas +* REDESIGNED: GuiToggleGroup() to process rows/cols with no need for GuiTextSplit() +* REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion +* REDESIGNED: WARNING: TEXT_LINE_SPACING does not consider text height, only lines spacing +* REDESIGNED: WARNING: GuiMessageBox(), added parameter for btn return, unify result +* REDESIGNED: WARNING: GuiTextInputBox(), added parameter for btn return, unify result +* REVIEWED: GuiLoadIconsFromMemory(), fixed memory issues * REVIEWED: Controls using text labels to use LABEL properties * REVIEWED: Replaced sprintf() by snprintf() for more safety * REVIEWED: GuiTabBar(), close tab with mouse middle button @@ -165,8 +179,6 @@ * REVIEWED: GuiProgressBar(), improved borders computing * REVIEWED: GuiTextBox(), multiple improvements: autocursor and more * REVIEWED: Functions descriptions, removed wrong return value reference -* REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion -* REDESIGNED: WARNING: TEXT_LINE_SPACING does not consider text height, only lines spacing * * 4.0 (12-Sep-2023) ADDED: GuiToggleSlider() * ADDED: GuiColorPickerHSV() and GuiColorPanelHSV() @@ -273,7 +285,7 @@ * 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria * * DEPENDENCIES: -* raylib 5.6-dev - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing +* raylib 6.1-dev - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing * * STANDALONE MODE: * By default raygui depends on raylib mostly for the inputs and the drawing functionality but that dependency can be disabled @@ -340,10 +352,10 @@ #ifndef RAYGUI_H #define RAYGUI_H -#define RAYGUI_VERSION_MAJOR 4 -#define RAYGUI_VERSION_MINOR 5 +#define RAYGUI_VERSION_MAJOR 5 +#define RAYGUI_VERSION_MINOR 0 #define RAYGUI_VERSION_PATCH 0 -#define RAYGUI_VERSION "5.0-dev" +#define RAYGUI_VERSION "5.0" #if !defined(RAYGUI_STANDALONE) #include "raylib.h" @@ -357,7 +369,13 @@ #elif defined(USE_LIBTYPE_SHARED) #define RAYGUIAPI __declspec(dllimport) // Using the library as a Win32 shared library (.dll) #endif - #define _CRT_SECURE_NO_WARNINGS // Disable unsafe warnings on scanf() functions in MSVC + #if !defined(_CRT_SECURE_NO_WARNINGS) + #define _CRT_SECURE_NO_WARNINGS // Disable unsafe warnings on scanf() functions in MSVC + #endif +#else + #if defined(BUILD_LIBTYPE_SHARED) + #define RAYGUIAPI __attribute__((visibility("default"))) // Building as a Unix shared library (.so/.dylib) + #endif #endif // Function specifiers definition @@ -377,8 +395,8 @@ #define RAYGUI_LOG(...) #endif +#if !defined(RAYGUI_STANDALONE) // Macros to define required UI inputs, including mapping to gamepad controls -// TODO: Define additionally required macros for missing inputs #if !defined(GUI_BUTTON_DOWN) #define GUI_BUTTON_DOWN (IsMouseButtonDown(MOUSE_LEFT_BUTTON) || IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) #endif @@ -389,13 +407,15 @@ #if !defined(GUI_BUTTON_PRESSED) #define GUI_BUTTON_PRESSED (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsGamepadButtonPressed(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) #endif -// TODO: WARNING: GuiTabBar() still requires IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON) +#if !defined(GUI_BUTTON_PRESSED_MID) + #define GUI_BUTTON_PRESSED_MID (IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON) || IsGamepadButtonPressed(0, GAMEPAD_BUTTON_RIGHT_FACE_UP)) +#endif #if !defined(GUI_BUTTON_RELEASED) #define GUI_BUTTON_RELEASED (IsMouseButtonReleased(MOUSE_LEFT_BUTTON) || IsGamepadButtonReleased(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) #endif #if !defined(GUI_SCROLL_DELTA) // Mapping to scroll delta changes - // TODO: Review inconsistencies between platforms + // TODO: Review mouse scroll inconsistencies between platforms #if defined(PLATFORM_WEB) // NOTE: Gamepad axis triggers not detected on web platform #define GUI_SCROLL_DELTA ((float)IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_TRIGGER_2) - (float)IsGamepadButtonDown(0, GAMEPAD_BUTTON_LEFT_TRIGGER_2)) @@ -415,6 +435,18 @@ #if !defined(GUI_INPUT_KEY) #define GUI_INPUT_KEY GetCharPressed() #endif +#else + #define GUI_BUTTON_DOWN 0 + #define GUI_BUTTON_DOWN_ALT 0 + #define GUI_BUTTON_PRESSED 0 + #define GUI_BUTTON_PRESSED_MID 0 + #define GUI_BUTTON_RELEASED 0 + #define GUI_SCROLL_DELTA 0 + #define GUI_POINTER_POSITION (Vector2){ 0 } + #define GUI_KEY_DOWN(key) 0 + #define GUI_KEY_PRESSED(key) 0 + #define GUI_INPUT_KEY 0 +#endif //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -449,6 +481,8 @@ unsigned char a; } Color; +#define BLANK (Color){ 0, 0, 0, 0 } // Blank (Transparent) + // Rectangle type typedef struct Rectangle { float x; @@ -457,7 +491,7 @@ float height; } Rectangle; - // TODO: Texture2D type is very coupled to raylib, required by Font type + // NOTE: Texture2D type is very coupled to raylib, required by Font type // It should be redesigned to be provided by user typedef struct Texture { unsigned int id; // OpenGL texture id @@ -488,7 +522,7 @@ Image image; // Character image data } GlyphInfo; - // TODO: Font type is very coupled to raylib, mostly required by GuiLoadStyle() + // NOTE: Font type is very coupled to raylib, mostly required by GuiLoadStyle() // It should be redesigned to be provided by user typedef struct Font { int baseSize; // Base size (default chars height) @@ -521,6 +555,15 @@ typedef struct GuiTextStyle { } GuiTextStyle; */ +// Gui control result +typedef enum { + RESULT_NONE = 0, + RESULT_PRESSED = 1, + RESULT_CHANGED = 2, + + RESULT_TAB_CLOSE = 4 // GuiTabBar(), tab close request +} GuiResult; + // Gui control state typedef enum { STATE_NORMAL = 0, @@ -553,88 +596,95 @@ typedef enum { } GuiTextWrapMode; // Gui controls +// NOTE: Up to 16 controls supported or 32 controls (v500) typedef enum { // Default -> populates to all controls when set - DEFAULT = 0, + DEFAULT = 0, // Basic controls - LABEL, // Used also for: LABELBUTTON - BUTTON, - TOGGLE, // Used also for: TOGGLEGROUP - SLIDER, // Used also for: SLIDERBAR, TOGGLESLIDER - PROGRESSBAR, - CHECKBOX, - COMBOBOX, - DROPDOWNBOX, - TEXTBOX, // Used also for: TEXTBOXMULTI - VALUEBOX, - CONTROL11, - LISTVIEW, - COLORPICKER, - SCROLLBAR, - STATUSBAR + LABEL = 1, // Used also for: LABELBUTTON + BUTTON = 2, + TOGGLE = 3, // Used also for: TOGGLEGROUP + SLIDER = 4, // Used also for: SLIDERBAR, TOGGLESLIDER + PROGRESSBAR = 5, + CHECKBOX = 6, + COMBOBOX = 7, + DROPDOWNBOX = 8, + TEXTBOX = 9, // Used also for: TEXTBOXMULTI + VALUEBOX = 10, + TABBAR = 11, + LISTVIEW = 12, + COLORPICKER = 13, + SCROLLBAR = 14, + STATUSBAR = 15 + // NOTE: More controls can be added if required } GuiControl; -// Gui base properties for every control -// NOTE: RAYGUI_MAX_PROPS_BASE properties (by default 16 properties) +// Controls BASE properties for every control (RAYGUI_MAX_PROPS_BASE = 16) +// NOTE: Properties required for all controls, DEFAULT control sets +// default values for them but they can be overriden per control typedef enum { - BORDER_COLOR_NORMAL = 0, // Control border color in STATE_NORMAL - BASE_COLOR_NORMAL, // Control base color in STATE_NORMAL - TEXT_COLOR_NORMAL, // Control text color in STATE_NORMAL - BORDER_COLOR_FOCUSED, // Control border color in STATE_FOCUSED - BASE_COLOR_FOCUSED, // Control base color in STATE_FOCUSED - TEXT_COLOR_FOCUSED, // Control text color in STATE_FOCUSED - BORDER_COLOR_PRESSED, // Control border color in STATE_PRESSED - BASE_COLOR_PRESSED, // Control base color in STATE_PRESSED - TEXT_COLOR_PRESSED, // Control text color in STATE_PRESSED - BORDER_COLOR_DISABLED, // Control border color in STATE_DISABLED - BASE_COLOR_DISABLED, // Control base color in STATE_DISABLED - TEXT_COLOR_DISABLED, // Control text color in STATE_DISABLED - BORDER_WIDTH = 12, // Control border size, 0 for no border - //TEXT_SIZE, // Control text size (glyphs max height) -> GLOBAL for all controls - //TEXT_SPACING, // Control text spacing between glyphs -> GLOBAL for all controls - //TEXT_LINE_SPACING, // Control text spacing between lines -> GLOBAL for all controls - TEXT_PADDING = 13, // Control text padding, not considering border - TEXT_ALIGNMENT = 14, // Control text horizontal alignment inside control text bound (after border and padding) - //TEXT_WRAP_MODE // Control text wrap-mode inside text bounds -> GLOBAL for all controls + BORDER_COLOR_NORMAL = 0, // Control border color in STATE_NORMAL + BASE_COLOR_NORMAL = 1, // Control base color in STATE_NORMAL + TEXT_COLOR_NORMAL = 2, // Control text color in STATE_NORMAL + BORDER_COLOR_FOCUSED = 3, // Control border color in STATE_FOCUSED + BASE_COLOR_FOCUSED = 4, // Control base color in STATE_FOCUSED + TEXT_COLOR_FOCUSED = 5, // Control text color in STATE_FOCUSED + BORDER_COLOR_PRESSED = 6, // Control border color in STATE_PRESSED + BASE_COLOR_PRESSED = 7, // Control base color in STATE_PRESSED + TEXT_COLOR_PRESSED = 8, // Control text color in STATE_PRESSED + BORDER_COLOR_DISABLED = 9, // Control border color in STATE_DISABLED + BASE_COLOR_DISABLED = 10, // Control base color in STATE_DISABLED + TEXT_COLOR_DISABLED = 11, // Control text color in STATE_DISABLED + BORDER_WIDTH = 12, // Control border size, 0 for no border + TEXT_PADDING = 13, // Control text padding, not considering border + TEXT_ALIGNMENT = 14, // Control text horizontal alignment inside control text bound (after border and padding): 0-Left, 1-Center, 2-Right + BASEPROP16 = 15 // Not used yet... } GuiControlProperty; -// TODO: Which text styling properties should be global or per-control? -// At this moment TEXT_PADDING and TEXT_ALIGNMENT is configured and saved per control while -// TEXT_SIZE, TEXT_SPACING, TEXT_LINE_SPACING, TEXT_ALIGNMENT_VERTICAL, TEXT_WRAP_MODE are global and -// should be configured by user as needed while defining the UI layout -// Gui extended properties depend on control -// NOTE: RAYGUI_MAX_PROPS_EXTENDED properties (by default, max 8 properties) +// WARNING: Some properties have been chosen to be global with DEFAULT - EXTENDED properties: +// - TEXT_SIZE, // Control text size (glyphs max height) +// - TEXT_SPACING, // Control text spacing between glyphs +// - TEXT_LINE_SPACING, // Control text spacing between lines +// - TEXT_WRAP_MODE // Control text wrap-mode inside text bounds +// +// While other properties can be setup per globally (DEFAULT) or per control: +// - TEXT_PADDING // Control text padding, not considering border +// - TEXT_ALIGNMENT // Control text horizontal alignment inside control text bound + + +// Controls EXTENDED properties (RAYGUI_MAX_PROPS_EXTENDED = 8) +// WARNING: Only 8 slots vailable for those properties per control, including DEFAULT //---------------------------------------------------------------------------------- -// DEFAULT extended properties -// NOTE: Those properties are common to all controls or global -// WARNING: Only 8 slots vailable for those properties by default +// DEFAULT control, extended properties +// NOTE: Those properties are global for all controls, they can not be setup per control typedef enum { - TEXT_SIZE = 16, // Text size (glyphs max height) - TEXT_SPACING, // Text spacing between glyphs - LINE_COLOR, // Line control color - BACKGROUND_COLOR, // Background color - TEXT_LINE_SPACING, // Text spacing between lines - TEXT_ALIGNMENT_VERTICAL, // Text vertical alignment inside text bounds (after border and padding) - TEXT_WRAP_MODE // Text wrap-mode inside text bounds - //TEXT_DECORATION // Text decoration: 0-None, 1-Underline, 2-Line-through, 3-Overline - //TEXT_DECORATION_THICK // Text decoration line thickness + TEXT_SIZE = 16, // Text size (glyphs max height) + TEXT_SPACING = 17, // Text spacing between glyphs + LINE_COLOR = 18, // Line control color + BACKGROUND_COLOR = 19, // Background color + TEXT_LINE_SPACING = 20, // Text spacing between lines + TEXT_ALIGNMENT_VERTICAL = 21, // Text vertical alignment inside text bounds (after border and padding): 0-Top, 1-Middle, 2-Bottom + TEXT_WRAP_MODE = 22, // Text wrap-mode inside text bounds + EXTPROP08 = 23 // Not used yet... } GuiDefaultProperty; -// Other possible text properties: -// TEXT_WEIGHT // Normal, Italic, Bold -> Requires specific font change -// TEXT_INDENT // Text indentation -> Now using TEXT_PADDING... +// Other possible text extended properties: +// TEXT_DECORATION // Text decoration: 0-None, 1-Underline, 2-Line-through, 3-Overline +// TEXT_DECORATION_THICK // Text decoration line thickness +// TEXT_FONT_WEIGHT // Text font weight: 0-Normal, 1-Bold, 2-Italic -> Requires specific font change // Label //typedef enum { } GuiLabelProperty; -// Button/Spinner +// Button //typedef enum { } GuiButtonProperty; // Toggle/ToggleGroup typedef enum { GROUP_PADDING = 16, // ToggleGroup separation between toggles + GROUP_WIDTH_FULL // ToggleGroup bounds width considers all items: 0-Width per item, 1-Full width } GuiToggleProperty; // Slider/SliderBar @@ -646,7 +696,7 @@ typedef enum { // ProgressBar typedef enum { PROGRESS_PADDING = 16, // ProgressBar internal padding - PROGRESS_SIDE, // ProgressBar increment side: 0-left->right, 1-right-left + PROGRESS_SIDE, // ProgressBar increment side: 0-Left->Right, 1-Right->Left } GuiProgressBarProperty; // ScrollBar @@ -675,12 +725,12 @@ typedef enum { ARROW_PADDING = 16, // DropdownBox arrow separation from border and items DROPDOWN_ITEMS_SPACING, // DropdownBox items separation DROPDOWN_ARROW_HIDDEN, // DropdownBox arrow hidden - DROPDOWN_ROLL_UP // DropdownBox roll up flag (default rolls down) + DROPDOWN_ROLL_UP // DropdownBox roll up flag: 0-Roll down, 1-Roll up } GuiDropdownBoxProperty; // TextBox/TextBoxMulti/ValueBox/Spinner typedef enum { - TEXT_READONLY = 16, // TextBox in read-only mode: 0-text editable, 1-text no-editable + TEXT_READONLY = 16, // TextBox in read-only mode: 0-Text editable, 1-Text read-only } GuiTextBoxProperty; // ValueBox/Spinner @@ -689,31 +739,35 @@ typedef enum { SPINNER_BUTTON_SPACING, // Spinner buttons separation } GuiValueBoxProperty; -// Control11 -//typedef enum { } GuiControl11Property; +// TabBar +typedef enum { + TAB_ITEMS_WIDTH = 16, // TabBar tab items width + TAB_CLOSE_BUTTON, // TabBar tab close button: 0-Not shown, 1-Shown + TAB_LINE_SIDE, // TabBar tabs side: 0-Bottom, 1-Top +} GuiTabBarProperty; // ListView +#define SCROLLBAR_LEFT_SIDE 0 +#define SCROLLBAR_RIGHT_SIDE 1 + typedef enum { LIST_ITEMS_HEIGHT = 16, // ListView items height LIST_ITEMS_SPACING, // ListView items separation SCROLLBAR_WIDTH, // ListView scrollbar size (usually width) - SCROLLBAR_SIDE, // ListView scrollbar side (0-SCROLLBAR_LEFT_SIDE, 1-SCROLLBAR_RIGHT_SIDE) + SCROLLBAR_SIDE, // ListView scrollbar side: 0-Left side, 1-Right Side LIST_ITEMS_BORDER_NORMAL, // ListView items border enabled in normal state LIST_ITEMS_BORDER_WIDTH // ListView items border width } GuiListViewProperty; // ColorPicker typedef enum { - COLOR_SELECTOR_SIZE = 16, + COLOR_SELECTOR_SIZE = 16, // ColorPicker selector square size HUEBAR_WIDTH, // ColorPicker right hue bar width HUEBAR_PADDING, // ColorPicker right hue bar separation from panel HUEBAR_SELECTOR_HEIGHT, // ColorPicker right hue bar selector height HUEBAR_SELECTOR_OVERFLOW // ColorPicker right hue bar selector overflow } GuiColorPickerProperty; -#define SCROLLBAR_LEFT_SIDE 0 -#define SCROLLBAR_RIGHT_SIDE 1 - //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- @@ -747,6 +801,7 @@ RAYGUIAPI int GuiGetStyle(int control, int property); // Get one style // Styles loading functions RAYGUIAPI void GuiLoadStyle(const char *fileName); // Load style file over global style variable (.rgs) +RAYGUIAPI void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only) RAYGUIAPI void GuiLoadStyleDefault(void); // Load style default over global style // Tooltips management functions @@ -760,6 +815,7 @@ RAYGUIAPI const char *GuiIconText(int iconId, const char *text); // Get text wit RAYGUIAPI void GuiSetIconScale(int scale); // Set default icon drawing size RAYGUIAPI unsigned int *GuiGetIcons(void); // Get raygui icons data pointer RAYGUIAPI char **GuiLoadIcons(const char *fileName, bool loadIconsName); // Load raygui icons file (.rgi) into internal icons data +RAYGUIAPI char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName); // Load raygui icons file (.rgi) from memory into internal icons data RAYGUIAPI void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color); // Draw icon using pixel size at specified position #endif @@ -773,7 +829,6 @@ RAYGUIAPI int GuiWindowBox(Rectangle bounds, const char *title); RAYGUIAPI int GuiGroupBox(Rectangle bounds, const char *text); // Group Box control with text name RAYGUIAPI int GuiLine(Rectangle bounds, const char *text); // Line separator control, could contain text RAYGUIAPI int GuiPanel(Rectangle bounds, const char *text); // Panel control, useful to group controls -RAYGUIAPI int GuiTabBar(Rectangle bounds, char **text, int count, int *active); // Tab Bar control, returns TAB to be closed or -1 RAYGUIAPI int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view); // Scroll Panel control // Basic controls set @@ -801,15 +856,17 @@ RAYGUIAPI int GuiGrid(Rectangle bounds, const char *text, float spacing, int sub // Advance controls set RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active); // List View control -RAYGUIAPI int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus); // List View with extended parameters -RAYGUIAPI int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons); // Message Box control, displays a message -RAYGUIAPI int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive); // Text Input Box control, ask for text, supports secret -RAYGUIAPI int GuiColorPicker(Rectangle bounds, const char *text, Color *color); // Color Picker control (multiple color controls) +RAYGUIAPI int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus); // List View control, using text entries list and returning focus entry +RAYGUIAPI int GuiTabBar(Rectangle bounds, const char *text, int *hscroll, int *active); // Tab Bar control +RAYGUIAPI int GuiTabBarEx(Rectangle bounds, char **text, int count, int *hscroll, int *active, int *focus); // Tab Bar control, using text entries list and returning focus entry +RAYGUIAPI int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *btnText, int *btnActive); // Message Box control, displays a message +RAYGUIAPI int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, char *text, int textSize, const char *btnText, int *btnActive, bool *secretViewActive); // Text Input Box control, ask for text, supports secret +RAYGUIAPI int GuiColorPicker(Rectangle bounds, const char *text, Color *color); // Color Picker control, includes Color bar controls RAYGUIAPI int GuiColorPanel(Rectangle bounds, const char *text, Color *color); // Color Panel control RAYGUIAPI int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha); // Color Bar Alpha control RAYGUIAPI int GuiColorBarHue(Rectangle bounds, const char *text, float *value); // Color Bar Hue control -RAYGUIAPI int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Picker control that avoids conversion to RGB on each call (multiple color controls) -RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control that updates Hue-Saturation-Value color value, used by GuiColorPickerHSV() +RAYGUIAPI int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Picker control, using Hue-Saturation-Value color data, includes Color bar controls +RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control, using Hue-Saturation-Value color data //---------------------------------------------------------------------------------------------------------- #if !defined(RAYGUI_NO_ICONS) @@ -1069,16 +1126,17 @@ typedef enum { ICON_CONE = 247, ICON_ELLIPSOID = 248, ICON_CAPSULE = 249, - ICON_250 = 250, - ICON_251 = 251, - ICON_252 = 252, - ICON_253 = 253, - ICON_254 = 254, - ICON_255 = 255 + ICON_FILETYPE_FONT = 250, + ICON_FILETYPE_3D = 251, + ICON_FILETYPE_CODE_XML = 252, + ICON_FILETYPE_CODE_C = 253, + ICON_FILETYPE_CODE_PYTHON = 254, + ICON_FILETYPE_CODE_JS = 255, + ICON_FILETYPE_ICON = 256, } GuiIconName; #endif -#endif +#endif // RAYGUI_NO_ICONS #if defined(__cplusplus) } // Prevents name mangling of functions @@ -1094,11 +1152,11 @@ typedef enum { #if defined(RAYGUI_IMPLEMENTATION) -#include // required for: isspace() [GuiTextBox()] #include // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()] #include // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy() #include // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()] #include // Required for: roundf() [GuiColorPicker()] +#include // Required for: isspace() [GuiTextBox()] // Allow custom memory allocators #if defined(RAYGUI_MALLOC) || defined(RAYGUI_CALLOC) || defined(RAYGUI_FREE) @@ -1127,9 +1185,11 @@ typedef enum { #if !defined(RAYGUI_NO_ICONS) && !defined(RAYGUI_CUSTOM_ICONS) // Embedded icons, no external file provided -#define RAYGUI_ICON_SIZE 16 // Size of icons in pixels (squared) -#define RAYGUI_ICON_MAX_ICONS 256 // Maximum number of icons -#define RAYGUI_ICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id +#define RAYGUI_ICON_SIZE 16 // Size of icons in pixels (squared) +#define RAYGUI_ICON_MAX_ICONS 512 // Maximum number of icons +#define RAYGUI_ICON_MAX_FONT_BACKED 257 // Maximum number of icons to back in font atlas +#define RAYGUI_ICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id +#define RAYGUI_ICON_FONT_ATLAS_PADDING 1 // Padding between backed icons in font atlas // Icons data is defined by bit array (every bit represents one pixel) // Those arrays are stored as unsigned int data arrays, so, @@ -1147,7 +1207,7 @@ typedef enum { // NOTE 2: A different icon set could be loaded over this array using GuiLoadIcons(), // but loaded icons set must be same RAYGUI_ICON_SIZE and no more than RAYGUI_ICON_MAX_ICONS // -// guiIcons size is by default: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 KB +// guiIcons size is by default: 512*(16*16/32) = 16384 bytes = 16 KB //---------------------------------------------------------------------------------- static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_NONE @@ -1400,18 +1460,20 @@ static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = 0x00800000, 0x01400140, 0x02200220, 0x04100410, 0x08080808, 0x1c1c13e4, 0x08081004, 0x000007f0, // ICON_CONE 0x00000000, 0x07e00000, 0x20841918, 0x40824082, 0x40824082, 0x19182084, 0x000007e0, 0x00000000, // ICON_ELLIPSOID 0x00000000, 0x00000000, 0x20041ff8, 0x40024002, 0x40024002, 0x1ff82004, 0x00000000, 0x00000000, // ICON_CAPSULE - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_250 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_251 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_252 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_253 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_254 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_255 + 0x3ff00000, 0x201c2010, 0x21042004, 0x22842384, 0x264426c4, 0x2c242fe4, 0x20043e74, 0x00003ffc, // ICON_FILETYPE_FONT + 0x3ff00000, 0x201c2010, 0x20042004, 0x27742004, 0x29742944, 0x27742944, 0x20042004, 0x00003ffc, // ICON_FILETYPE_3D + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x24242244, 0x24242814, 0x20042244, 0x00003ffc, // ICON_FILETYPE_XML + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x21042f04, 0x21042104, 0x20042f04, 0x00003ffc, // ICON_FILETYPE_C + 0x3ff00000, 0x201c2010, 0x23842004, 0x2bf42a04, 0x2fd42814, 0x21c42054, 0x20042004, 0x00003ffc, // ICON_FILETYPE_PYTHON + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x22842ee4, 0x28a42e84, 0x20042e64, 0x00003ffc, // ICON_FILETYPE_JS + 0x3ff00000, 0x241c2010, 0x2a8c3104, 0x28242454, 0x2ed42004, 0x2a542a54, 0x20042ed4, 0x00003ffc, // ICON_FILETYPE_ICON + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_257 }; // NOTE: A pointer to current icons array should be defined static unsigned int *guiIconsPtr = guiIcons; -#endif // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS +#endif // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS #ifndef RAYGUI_ICON_SIZE #define RAYGUI_ICON_SIZE 0 @@ -1435,10 +1497,12 @@ typedef enum { BORDER = 0, BASE, TEXT, OTHER } GuiPropertyElement; static GuiState guiState = STATE_NORMAL; // Gui global state, if !STATE_NORMAL, forces defined state static Font guiFont = { 0 }; // Gui current font (WARNING: highly coupled to raylib) +static char guiFontName[32] = { 0 }; // Gui font filename, can be loaded from .rgs (Version: >=600) static bool guiLocked = false; // Gui lock state (no inputs processed) static float guiAlpha = 1.0f; // Gui controls transparency static unsigned int guiIconScale = 1; // Gui icon default scale (if icons enabled) +static unsigned int guiIconFontOffsetY = 0; // Gui icon font atlas offset (if icons backed) static bool guiTooltip = false; // Tooltip enabled/disabled static const char *guiTooltipPtr = NULL; // Tooltip string pointer (string provided by user) @@ -1519,22 +1583,22 @@ static int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle( static void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list static unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle() + +static Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font //------------------------------------------------------------------------------- // raylib functions already implemented in raygui //------------------------------------------------------------------------------- static Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value +static Color Fade(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f static int ColorToInt(Color color); // Returns hexadecimal value for a Color static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed' -static char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings static int TextToInteger(const char *text); // Get integer value from text static float TextToFloat(const char *text); // Get float value from text static int GetCodepointNext(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded text static const char *CodepointToUTF8(int codepoint, int *byteSize); // Encode codepoint into UTF-8 text (char array size returned as parameter) - -static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2); // Draw rectangle vertical gradient //------------------------------------------------------------------------------- #endif // RAYGUI_STANDALONE @@ -1542,22 +1606,22 @@ static void DrawRectangleGradientV(int posX, int posY, int width, int height, Co //---------------------------------------------------------------------------------- // Module Internal Functions Declaration //---------------------------------------------------------------------------------- -static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only) - +static int GetLineWidth(const char *text); // Get text line width (stops at '\n' or '\0') static Rectangle GetTextBounds(int control, Rectangle bounds); // Get text bounds considering control bounds static const char *GetTextIcon(const char *text, int *iconId); // Get text icon if provided and move text cursor -static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint); // Gui draw text using default font -static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // Gui draw rectangle using default raygui style +static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint); // Gui draw text using default font +static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // Gui draw rectangle using default raygui style -static char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow); // Split controls text into multiple strings +static char **GuiTextSplit(const char *text, char delimiter, int *count); // Split controls text into multiple strings static Vector3 ConvertHSVtoRGB(Vector3 hsv); // Convert color data from HSV to RGB static Vector3 ConvertRGBtoHSV(Vector3 rgb); // Convert color data from RGB to HSV -static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel() static void GuiTooltip(Rectangle controlRec); // Draw tooltip using control rec position +static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel() +static int GuiFontIconBaking(Image *imFont, Font font, Rectangle *whiteRec); // Update font image atlas to append raygui icons -static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor +static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor //---------------------------------------------------------------------------------- // Gui Setup Functions Definition @@ -1600,7 +1664,7 @@ void GuiSetFont(Font font) { if (font.texture.id > 0) { - // NOTE: If a font is tried to be set but default style has not been lazily loaded first, + // NOTE: If a font is tried to be set but default style has not been lazily loaded first, // it will be overwritten, so default style loading needs to be forced first if (!guiStyleLoaded) GuiLoadStyleDefault(); @@ -1651,7 +1715,7 @@ int GuiWindowBox(Rectangle bounds, const char *title) #define RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT 18 #endif - int result = 0; + int result = RESULT_NONE; //GuiState state = guiState; int statusBarHeight = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT; @@ -1673,11 +1737,15 @@ int GuiWindowBox(Rectangle bounds, const char *title) // Draw control //-------------------------------------------------------------------- GuiPanel(windowPanel, NULL); // Draw window base + + int tempTextAlignment = GuiGetStyle(STATUSBAR, TEXT_ALIGNMENT); + GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); GuiStatusBar(statusBar, title); // Draw window header as status bar + GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, tempTextAlignment); // Draw window close button int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); - int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); GuiSetStyle(BUTTON, BORDER_WIDTH, 1); GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); #if defined(RAYGUI_NO_ICONS) @@ -1689,7 +1757,7 @@ int GuiWindowBox(Rectangle bounds, const char *title) GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); //-------------------------------------------------------------------- - return result; // Window close button clicked: result = 1 + return result; } // Group Box control with text name @@ -1699,7 +1767,7 @@ int GuiGroupBox(Rectangle bounds, const char *text) #define RAYGUI_GROUPBOX_LINE_THICK 1 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Draw control @@ -1724,7 +1792,7 @@ int GuiLine(Rectangle bounds, const char *text) #define RAYGUI_LINE_TEXT_PADDING 4 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; Color color = GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)); @@ -1757,7 +1825,7 @@ int GuiPanel(Rectangle bounds, const char *text) #define RAYGUI_PANEL_BORDER_WIDTH 1 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Text will be drawn as a header bar (if provided) @@ -1773,7 +1841,7 @@ int GuiPanel(Rectangle bounds, const char *text) // Draw control //-------------------------------------------------------------------- - if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar + if (text != NULL) result = GuiStatusBar(statusBar, text); // Draw panel header as status bar GuiDrawRectangle(bounds, RAYGUI_PANEL_BORDER_WIDTH, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)), GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BASE_COLOR_DISABLED : (int)BACKGROUND_COLOR))); @@ -1782,81 +1850,6 @@ int GuiPanel(Rectangle bounds, const char *text) return result; } -// Tab Bar control -// NOTE: Using GuiToggle() for the TABS -int GuiTabBar(Rectangle bounds, char **text, int count, int *active) -{ - #define RAYGUI_TABBAR_ITEM_WIDTH 148 - - int result = -1; - //GuiState state = guiState; - - Rectangle tabBounds = { bounds.x, bounds.y, RAYGUI_TABBAR_ITEM_WIDTH, bounds.height }; - - if (*active < 0) *active = 0; - else if (*active > count - 1) *active = count - 1; - - int offsetX = 0; // Required in case tabs go out of screen - offsetX = (*active + 2)*RAYGUI_TABBAR_ITEM_WIDTH - GetScreenWidth(); - if (offsetX < 0) offsetX = 0; - - bool toggle = false; // Required for individual toggles - - // Draw control - //-------------------------------------------------------------------- - for (int i = 0; i < count; i++) - { - tabBounds.x = bounds.x + (RAYGUI_TABBAR_ITEM_WIDTH + 4)*i - offsetX; - - if (tabBounds.x < GetScreenWidth()) - { - // Draw tabs as toggle controls - int textAlignment = GuiGetStyle(TOGGLE, TEXT_ALIGNMENT); - int textPadding = GuiGetStyle(TOGGLE, TEXT_PADDING); - GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); - GuiSetStyle(TOGGLE, TEXT_PADDING, 8); - - if (i == (*active)) - { - toggle = true; - GuiToggle(tabBounds, text[i], &toggle); - } - else - { - toggle = false; - GuiToggle(tabBounds, text[i], &toggle); - if (toggle) *active = i; - } - - // Close tab with middle mouse button pressed - if (CheckCollisionPointRec(GUI_POINTER_POSITION, tabBounds) && IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON)) result = i; - - GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding); - GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment); - - // Draw tab close button - // NOTE: Only draw close button for current tab: if (CheckCollisionPointRec(mousePosition, tabBounds)) - int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); - int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); - GuiSetStyle(BUTTON, BORDER_WIDTH, 1); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); -#if defined(RAYGUI_NO_ICONS) - if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, "x")) result = i; -#else - if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, GuiIconText(ICON_CROSS_SMALL, NULL))) result = i; -#endif - GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); - } - } - - // Draw tab-bar bottom line - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, 1 }, 0, BLANK, GetColor(GuiGetStyle(TOGGLE, BORDER_COLOR_NORMAL))); - //-------------------------------------------------------------------- - - return result; // Return as result the current TAB closing requested -} - // Scroll Panel control int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view) { @@ -1864,7 +1857,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector #define RAYGUI_MIN_SCROLLBAR_HEIGHT 40 #define RAYGUI_MIN_MOUSE_WHEEL_SPEED 20 - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; Rectangle temp = { 0 }; @@ -1921,7 +1914,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector float horizontalMin = hasHorizontalScrollBar? ((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH); float horizontalMax = hasHorizontalScrollBar? content.width - bounds.width + (float)verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH) - (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)verticalScrollBarWidth : 0) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); - float verticalMin = hasVerticalScrollBar? 0.0f : -1.0f; + float verticalMin = -(float)GuiGetStyle(DEFAULT, BORDER_WIDTH); float verticalMax = hasVerticalScrollBar? content.height - bounds.height + (float)horizontalScrollBarWidth + (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); // Update control @@ -1971,7 +1964,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector // Draw control //-------------------------------------------------------------------- - if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar + if (text != NULL) result = GuiStatusBar(statusBar, text); // Draw panel header as status bar GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background @@ -2018,7 +2011,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector // Label control int GuiLabel(Rectangle bounds, const char *text) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Update control @@ -2037,7 +2030,7 @@ int GuiLabel(Rectangle bounds, const char *text) // Button control, returns true when clicked int GuiButton(Rectangle bounds, const char *text) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Update control @@ -2052,7 +2045,7 @@ int GuiButton(Rectangle bounds, const char *text) if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; - if (GUI_BUTTON_RELEASED) result = 1; + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; } } //-------------------------------------------------------------------- @@ -2065,14 +2058,14 @@ int GuiButton(Rectangle bounds, const char *text) if (state == STATE_FOCUSED) GuiTooltip(bounds); //------------------------------------------------------------------ - return result; // Button pressed: result = 1 + return result; } // Label button control int GuiLabelButton(Rectangle bounds, const char *text) { + int result = RESULT_NONE; GuiState state = guiState; - bool pressed = false; // NOTE: Force bounds.width to be all text float textWidth = (float)GuiGetTextWidth(text); @@ -2090,7 +2083,7 @@ int GuiLabelButton(Rectangle bounds, const char *text) if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; - if (GUI_BUTTON_RELEASED) pressed = true; + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; } } //-------------------------------------------------------------------- @@ -2100,13 +2093,13 @@ int GuiLabelButton(Rectangle bounds, const char *text) GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); //-------------------------------------------------------------------- - return pressed; + return result; } // Toggle Button control int GuiToggle(Rectangle bounds, const char *text, bool *active) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; bool temp = false; @@ -2126,6 +2119,8 @@ int GuiToggle(Rectangle bounds, const char *text, bool *active) { state = STATE_NORMAL; *active = !(*active); + + result = RESULT_CHANGED; } else state = STATE_FOCUSED; } @@ -2154,68 +2149,110 @@ int GuiToggle(Rectangle bounds, const char *text, bool *active) // Toggle Group control int GuiToggleGroup(Rectangle bounds, const char *text, int *active) { - #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEMS) - #define RAYGUI_TOGGLEGROUP_MAX_ITEMS 32 + int result = RESULT_NONE; + + #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE) + #define RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE 256 #endif - int result = 0; - float initBoundsX = bounds.x; + // One toggle group item text + static char itemText[RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE] = { 0 }; + memset(itemText, 0, RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE); int temp = 0; + int prevActive = (active == NULL)? 0 : *active; if (active == NULL) active = &temp; bool toggle = false; // Required for individual toggles - // Get substrings items from text (items pointers) - int rows[RAYGUI_TOGGLEGROUP_MAX_ITEMS] = { 0 }; - int itemCount = 0; - char **items = GuiTextSplit(text, ';', &itemCount, rows); + const char *textPtr = text; + bool itemReady = false; + float initBoundsX = bounds.x; + float initBoundsY = bounds.y; - int prevRow = rows[0]; - - for (int i = 0; i < itemCount; i++) + if (GuiGetStyle(TOGGLE, GROUP_WIDTH_FULL)) { - if (prevRow != rows[i]) - { - bounds.x = initBoundsX; - bounds.y += (bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING)); - prevRow = rows[i]; - } + // Calculate item width considring all horizontal items + // NOTE: bounds.height still considers individual items height + int itemCount = 1; + for (int c = 0; textPtr[c] != '\0'; c++) { if (textPtr[c] == ';') itemCount++; } + bounds.width /= itemCount; + } - if (i == (*active)) + // Text parsing needed to consider potential row and col entries (vertical/horizontal layout) + // when '\n' found move vertically next toggle, when ';' found move horizontally + for (int c = 0, k = 0, itemIndex = 0, row = 0, col = 0, exit = 0; exit == 0; c++) + { + // Process text to get items one by one + // NOTE: Setting columns and rows index properly + if (textPtr[c] == '\n') { - toggle = true; - GuiToggle(bounds, items[i], &toggle); + row++; + col = 0; + itemReady = true; + } + else if (textPtr[c] == ';') + { + col++; + itemReady = true; + } + else if (textPtr[c] == '\0') + { + itemReady = true; + exit = 1; } else { - toggle = false; - GuiToggle(bounds, items[i], &toggle); - if (toggle) *active = i; + itemText[k] = textPtr[c]; + k++; } - bounds.x += (bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING)); + if (itemReady) + { + // When a next item is ready, draw its toggle + if (itemIndex == (*active)) + { + toggle = true; + GuiToggle(bounds, itemText, &toggle); + } + else + { + toggle = false; + GuiToggle(bounds, itemText, &toggle); + if (toggle) *active = itemIndex; + } + + // Calculate next item position + bounds.x = initBoundsX + col*(bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING)); + bounds.y = initBoundsY + row*(bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING)); + + itemIndex++; + itemReady = false; + memset(itemText, 0, k + 1); + k = 0; + } } + if (prevActive != *active) result = RESULT_CHANGED; + return result; } // Toggle Slider control extended int GuiToggleSlider(Rectangle bounds, const char *text, int *active) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; int temp = 0; + int prevActive = (active == NULL)? 0 : *active; if (active == NULL) active = &temp; - //bool toggle = false; // Required for individual toggles - // Get substrings items from text (items pointers) int itemCount = 0; char **items = NULL; - if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL); + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount); Rectangle slider = { 0, // Calculated later depending on the active toggle @@ -2246,6 +2283,8 @@ int GuiToggleSlider(Rectangle bounds, const char *text, int *active) if (*active >= itemCount) *active = 0; slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH) + (*active + 1)*GuiGetStyle(SLIDER, SLIDER_PADDING) + (*active)*slider.width; + + if (prevActive != *active) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -2277,7 +2316,7 @@ int GuiToggleSlider(Rectangle bounds, const char *text, int *active) // Check Box control, returns 1 when state changed int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; bool temp = false; @@ -2316,7 +2355,8 @@ int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) if (GUI_BUTTON_RELEASED) { *checked = !(*checked); - result = 1; + + result = RESULT_CHANGED; } } } @@ -2344,10 +2384,11 @@ int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) // Combo Box control int GuiComboBox(Rectangle bounds, const char *text, int *active) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; int temp = 0; + int prevActive = (active == NULL)? 0 : *active; if (active == NULL) active = &temp; bounds.width -= (GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH) + GuiGetStyle(COMBOBOX, COMBO_BUTTON_SPACING)); @@ -2357,7 +2398,7 @@ int GuiComboBox(Rectangle bounds, const char *text, int *active) // Get substrings items from text (items pointers, lengths and count) int itemCount = 0; - char **items = GuiTextSplit(text, ';', &itemCount, NULL); + char **items = GuiTextSplit(text, ';', &itemCount); if (*active < 0) *active = 0; else if (*active > (itemCount - 1)) *active = itemCount - 1; @@ -2371,16 +2412,18 @@ int GuiComboBox(Rectangle bounds, const char *text, int *active) if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + if (GUI_BUTTON_PRESSED) { *active += 1; if (*active >= itemCount) *active = 0; // Cyclic combobox } - - if (GUI_BUTTON_DOWN) state = STATE_PRESSED; - else state = STATE_FOCUSED; } } + + if (prevActive != *active) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -2409,10 +2452,11 @@ int GuiComboBox(Rectangle bounds, const char *text, int *active) // NOTE: Returns mouse click int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; int temp = 0; + int prevActive = (active == NULL)? 0 : *active; if (active == NULL) active = &temp; int itemSelected = *active; @@ -2423,7 +2467,7 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod // Get substrings items from text (items pointers, lengths and count) int itemCount = 0; - char **items = GuiTextSplit(text, ';', &itemCount, NULL); + char **items = GuiTextSplit(text, ';', &itemCount); Rectangle boundsOpen = bounds; boundsOpen.height = (itemCount + 1)*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); @@ -2523,7 +2567,8 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 }, TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); #else - GuiDrawText(direction? "#121#" : "#120#", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 }, + GuiDrawText(direction? GuiIconText(ICON_ARROW_UP_FILL, NULL) : GuiIconText(ICON_ARROW_DOWN_FILL, NULL), + RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 }, TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); // ICON_ARROW_DOWN_FILL #endif } @@ -2531,8 +2576,9 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod *active = itemSelected; - // TODO: Use result to return more internal states: mouse-press out-of-bounds, mouse-press over selected-item... - return result; // Mouse click: result = 1 + if (prevActive != *active) result = RESULT_CHANGED; + + return result; } // Text Box control @@ -2546,10 +2592,10 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) #define RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY 1 // Frames delay for autocursor movement #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; - bool multiline = false; // TODO: Consider multiline text input + bool multiline = false; int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); Rectangle textBounds = GetTextBounds(TEXTBOX, bounds); @@ -2596,7 +2642,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) { // GLOBAL: Auto-cursor movement logic // NOTE: Keystrokes are handled repeatedly when button is held down for some time - if (GUI_KEY_DOWN(KEY_LEFT) || GUI_KEY_DOWN(KEY_RIGHT) || GUI_KEY_DOWN(KEY_UP) || GUI_KEY_DOWN(KEY_DOWN) || GUI_KEY_DOWN(KEY_BACKSPACE) || GUI_KEY_DOWN(KEY_DELETE)) autoCursorCounter++; + if (GUI_KEY_DOWN(KEY_LEFT) || GUI_KEY_DOWN(KEY_RIGHT) || + GUI_KEY_DOWN(KEY_UP) || GUI_KEY_DOWN(KEY_DOWN) || + GUI_KEY_DOWN(KEY_BACKSPACE) || GUI_KEY_DOWN(KEY_DELETE)) autoCursorCounter++; else autoCursorCounter = 0; bool autoCursorShouldTrigger = (autoCursorCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN) && ((autoCursorCounter % RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0); @@ -2654,6 +2702,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) textBoxCursorIndex += pasteLength; textLength += pasteLength; text[textLength] = '\0'; + + //result = RESULT_CHANGED; } } } @@ -2672,6 +2722,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) // Make sure text last character is EOL text[textLength] = '\0'; + + //result = RESULT_CHANGED; } // Move cursor to start @@ -2694,8 +2746,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) bool puctuation = ispunct(nextCodepoint & 0xff); while (offset < textLength) { - if ((puctuation && !ispunct(nextCodepoint & 0xff)) || (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff)))) - break; + if ((puctuation && !ispunct(nextCodepoint & 0xff)) || + (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff)))) break; + offset += nextCodepointSize; accCodepointSize += nextCodepointSize; nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); @@ -2715,9 +2768,11 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) for (int i = offset; i <= textLength; i++) text[i - accCodepointSize] = text[i]; textLength -= accCodepointSize; - } - else if ((textLength > textBoxCursorIndex) && (GUI_KEY_PRESSED(KEY_DELETE) || (GUI_KEY_DOWN(KEY_DELETE) && autoCursorShouldTrigger))) + //result = RESULT_CHANGED; + } + else if ((textLength > textBoxCursorIndex) && (GUI_KEY_PRESSED(KEY_DELETE) || + (GUI_KEY_DOWN(KEY_DELETE) && autoCursorShouldTrigger))) { // Delete single codepoint from text, after current cursor position @@ -2728,10 +2783,13 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) for (int i = textBoxCursorIndex + nextCodepointSize; i <= textLength; i++) text[i - nextCodepointSize] = text[i]; textLength -= nextCodepointSize; + + //result = RESULT_CHANGED; } // Delete related codepoints from text, before current cursor position - if ((textBoxCursorIndex > 0) && GUI_KEY_PRESSED(KEY_BACKSPACE) && (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) + if ((textBoxCursorIndex > 0) && GUI_KEY_PRESSED(KEY_BACKSPACE) && + (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) { int offset = textBoxCursorIndex; int accCodepointSize = 0; @@ -2754,7 +2812,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) while (offset > 0) { prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize); - if ((puctuation && !ispunct(prevCodepoint & 0xff)) || (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break; + if ((puctuation && !ispunct(prevCodepoint & 0xff)) || + (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break; offset -= prevCodepointSize; accCodepointSize += prevCodepointSize; @@ -2765,8 +2824,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) textLength -= accCodepointSize; textBoxCursorIndex -= accCodepointSize; - } + //result = RESULT_CHANGED; + } else if ((textBoxCursorIndex > 0) && (GUI_KEY_PRESSED(KEY_BACKSPACE) || (GUI_KEY_DOWN(KEY_BACKSPACE) && autoCursorShouldTrigger))) { // Delete single codepoint from text, before current cursor position @@ -2780,6 +2840,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) textLength -= prevCodepointSize; textBoxCursorIndex -= prevCodepointSize; + + //result = RESULT_CHANGED; } // Move cursor position with keys @@ -2862,7 +2924,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) } // Move cursor position with mouse - if (CheckCollisionPointRec(mousePosition, textBounds)) // Mouse hover text + if (CheckCollisionPointRec(mousePosition, textBounds)) { float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/(float)guiFont.baseSize; int codepointIndex = 0; @@ -2915,7 +2977,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) { textBoxCursorIndex = 0; // GLOBAL: Reset the shared cursor index autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes - result = 1; + + //*editMode = false; + result = RESULT_PRESSED; } } else @@ -2928,7 +2992,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) { textBoxCursorIndex = textLength; // GLOBAL: Place cursor index to the end of current text autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes - result = 1; + + //*editMode = true; + result = RESULT_PRESSED; } } } @@ -2963,7 +3029,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) else if (state == STATE_FOCUSED) GuiTooltip(bounds); //-------------------------------------------------------------------- - return result; // Mouse button pressed: result = 1 + return result; } /* @@ -3061,21 +3127,24 @@ int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); //-------------------------------------------------------------------- + //if (tempValue != *value) result = RESULT_CHANGED; // WARNING: Stops editing + *value = tempValue; + return result; } // Value Box control, updates input text with numbers -// NOTE: Requires static variables: frameCounter int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) { #if !defined(RAYGUI_VALUEBOX_MAX_CHARS) #define RAYGUI_VALUEBOX_MAX_CHARS 32 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; + //int prevValue = *value; char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = { 0 }; snprintf(textValue, RAYGUI_VALUEBOX_MAX_CHARS + 1, "%i", *value); @@ -3162,7 +3231,7 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in if (*value > maxValue) *value = maxValue; else if (*value < minValue) *value = minValue; - result = 1; + result = RESULT_PRESSED; } } else @@ -3173,10 +3242,13 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in if (CheckCollisionPointRec(mousePoint, bounds)) { state = STATE_FOCUSED; - if (GUI_BUTTON_PRESSED) result = 1; + + if (GUI_BUTTON_PRESSED) result = RESULT_PRESSED; } } } + + //if (prevValue != *value) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3207,18 +3279,16 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in } // Floating point Value Box control, updates input val_str with numbers -// NOTE: Requires static variables: frameCounter int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode) { #if !defined(RAYGUI_VALUEBOX_MAX_CHARS) #define RAYGUI_VALUEBOX_MAX_CHARS 32 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; - //char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0"; - //snprintf(textValue, sizeof(textValue), "%2.2f", *value); + //float prevValue = *value; Rectangle textBounds = { 0 }; if (text != NULL) @@ -3303,17 +3373,21 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float if (valueHasChanged) *value = TextToFloat(textValue); - if ((GUI_KEY_PRESSED(KEY_ENTER) || GUI_KEY_PRESSED(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && GUI_BUTTON_PRESSED)) result = 1; + if ((GUI_KEY_PRESSED(KEY_ENTER) || GUI_KEY_PRESSED(KEY_KP_ENTER)) || + (!CheckCollisionPointRec(mousePoint, bounds) && GUI_BUTTON_PRESSED)) result = RESULT_PRESSED; } else { if (CheckCollisionPointRec(mousePoint, bounds)) { state = STATE_FOCUSED; - if (GUI_BUTTON_PRESSED) result = 1; + + if (GUI_BUTTON_PRESSED) result = RESULT_PRESSED; } } } + + //if (prevValue != *value) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3336,8 +3410,7 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float } // Draw text label if provided - GuiDrawText(text, textBounds, - (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, + GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); //-------------------------------------------------------------------- @@ -3348,12 +3421,13 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float // NOTE: Other GuiSlider*() controls use this one int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; float temp = (maxValue - minValue)/2.0f; if (value == NULL) value = &temp; - float oldValue = *value; + + float prevValue = *value; int sliderWidth = GuiGetStyle(SLIDER, SLIDER_WIDTH); @@ -3404,10 +3478,6 @@ int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, flo else if (*value < minValue) *value = minValue; } - // Control value change check - if (oldValue == *value) result = 0; - else result = 1; - // Slider bar limits check float sliderValue = (((*value - minValue)/(maxValue - minValue))*(bounds.width - sliderWidth - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))); if (sliderWidth > 0) // Slider @@ -3423,6 +3493,8 @@ int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, flo slider.width = sliderValue; if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH); } + + if (prevValue != *value) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3465,7 +3537,7 @@ int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, flo // Slider Bar control extended, returns selected value int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) { - int result = 0; + int result = RESULT_NONE; int preSliderWidth = GuiGetStyle(SLIDER, SLIDER_WIDTH); GuiSetStyle(SLIDER, SLIDER_WIDTH, 0); result = GuiSlider(bounds, textLeft, textRight, value, minValue, maxValue); @@ -3477,11 +3549,12 @@ int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, // Progress Bar control extended, shows current progress value int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; float temp = (maxValue - minValue)/2.0f; if (value == NULL) value = &temp; + float prevValue = *value; // Progress bar Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), @@ -3494,6 +3567,8 @@ int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight // WARNING: Working with floats could lead to rounding issues if ((state != STATE_DISABLED)) progress.width = ((float)*value/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)); + + if (prevValue != *value) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3564,9 +3639,26 @@ int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight // Status Bar control int GuiStatusBar(Rectangle bounds, const char *text) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check checkbox state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + //if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + //else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; + } + } + //-------------------------------------------------------------------- + // Draw control //-------------------------------------------------------------------- GuiDrawRectangle(bounds, GuiGetStyle(STATUSBAR, BORDER_WIDTH), GetColor(GuiGetStyle(STATUSBAR, BORDER + (state*3))), GetColor(GuiGetStyle(STATUSBAR, BASE + (state*3)))); @@ -3579,7 +3671,7 @@ int GuiStatusBar(Rectangle bounds, const char *text) // Dummy rectangle control, intended for placeholding int GuiDummyRec(Rectangle bounds, const char *text) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Update control @@ -3593,6 +3685,8 @@ int GuiDummyRec(Rectangle bounds, const char *text) { if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; } } //-------------------------------------------------------------------- @@ -3609,25 +3703,26 @@ int GuiDummyRec(Rectangle bounds, const char *text) // List View control int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active) { - int result = 0; + int result = RESULT_NONE; int itemCount = 0; char **items = NULL; - if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL); + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount); result = GuiListViewEx(bounds, items, itemCount, scrollIndex, active, NULL); return result; } -// List View control with extended parameters +// List View control using text entries list and returning focus entry int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; int itemFocused = (focus == NULL)? -1 : *focus; int itemSelected = (active == NULL)? -1 : *active; + int prevActive = (active == NULL)? 0 : *active; // Check if scroll bar is needed bool useScrollBar = false; @@ -3765,35 +3860,132 @@ int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, in if (focus != NULL) *focus = itemFocused; if (scrollIndex != NULL) *scrollIndex = startIndex; + if (prevActive != *active) result = RESULT_CHANGED; + return result; } -// Color Panel control - Color (RGBA) variant +// Tab Bar control +int GuiTabBar(Rectangle bounds, const char *text, int *hscroll, int *active) +{ + int result = RESULT_NONE; + int itemCount = 0; + char **items = NULL; + + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount); + + result = GuiTabBarEx(bounds, items, itemCount, hscroll, active, NULL); + + return result; +} + +// Tab Bar control, using text entries list and returning focus entry +// NOTE: In case of tab close result, consider focused tab +// TODO: Reeplace GuiToggle() usage for custom implementation for the TABS +int GuiTabBarEx(Rectangle bounds, char **text, int count, int *hscroll, int *active, int *focus) +{ + int result = RESULT_NONE; + //GuiState state = guiState; + + int tabItemsWidth = GuiGetStyle(TABBAR, TAB_ITEMS_WIDTH); + Rectangle tabBounds = { bounds.x, bounds.y, (float)tabItemsWidth, bounds.height }; + + if (*active < 0) *active = 0; + else if (*active > count - 1) *active = count - 1; + + int prevActive = (active == NULL)? 0 : *active; + + int offsetX = 0; // Required in case tabs go out of screen + offsetX = (*active*tabItemsWidth) - GetScreenWidth(); + if (offsetX < 0) offsetX = 0; + + bool toggle = false; // Required for individual toggles + + // Draw control + //-------------------------------------------------------------------- + //if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) // TODO: Support disabled + + for (int i = 0; i < count; i++) + { + tabBounds.x = bounds.x + (tabItemsWidth + 4)*i + offsetX; + + if (tabBounds.x < GetScreenWidth()) + { + // Draw tabs as toggle controls + int textAlignment = GuiGetStyle(TOGGLE, TEXT_ALIGNMENT); + int textPadding = GuiGetStyle(TOGGLE, TEXT_PADDING); + GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(TOGGLE, TEXT_PADDING, 8); + + if (i == (*active)) + { + toggle = true; + GuiToggle(tabBounds, text[i], &toggle); + } + else + { + toggle = false; + GuiToggle(tabBounds, text[i], &toggle); + if (toggle) *active = i; + } + + // Close tab with middle mouse button pressed + if (CheckCollisionPointRec(GUI_POINTER_POSITION, tabBounds) && GUI_BUTTON_PRESSED_MID) result = RESULT_TAB_CLOSE; + + GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding); + GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment); + + if (GuiGetStyle(TABBAR, TAB_CLOSE_BUTTON)) + { + // Draw tab close button + // NOTE: Only draw close button for current tab: if (CheckCollisionPointRec(mousePosition, tabBounds)) + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 1); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); +#if defined(RAYGUI_NO_ICONS) + if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, "x")) result = RESULT_TAB_CLOSE; +#else + if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, + GuiIconText(ICON_CROSS_SMALL, NULL))) result = RESULT_TAB_CLOSE; +#endif + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); + } + } + } + + // Draw tab-bar bottom line + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, 1 }, 0, BLANK, GetColor(GuiGetStyle(TABBAR, BORDER_COLOR_NORMAL))); + //-------------------------------------------------------------------- + + // NOTE: In case of tab close result, consider focused tab + if ((result != RESULT_TAB_CLOSE) && (prevActive != *active)) result = RESULT_CHANGED; + + return result; +} + +// Color Panel control int GuiColorPanel(Rectangle bounds, const char *text, Color *color) { - int result = 0; + int result = RESULT_NONE; Vector3 vcolor = { (float)color->r/255.0f, (float)color->g/255.0f, (float)color->b/255.0f }; Vector3 hsv = ConvertRGBtoHSV(vcolor); - Vector3 prevHsv = hsv; // workaround to see if GuiColorPanelHSV modifies the hsv + Vector3 prevHsv = hsv; // NOTE: Workaround to see if GuiColorPanelHSV() modifies the hsv - GuiColorPanelHSV(bounds, text, &hsv); + result = GuiColorPanelHSV(bounds, text, &hsv); // Check if the hsv was changed, only then change the color // This is required, because the Color->HSV->Color conversion has precision errors // Thus the assignment from HSV to Color should only be made, if the HSV has a new user-entered value // Otherwise GuiColorPanel would often modify it's color without user input - // TODO: GuiColorPanelHSV could return 1 if the slider was dragged, to simplify this check - if (hsv.x != prevHsv.x || hsv.y != prevHsv.y || hsv.z != prevHsv.z) + if ((hsv.x != prevHsv.x) || (hsv.y != prevHsv.y) || (hsv.z != prevHsv.z)) { Vector3 rgb = ConvertHSVtoRGB(hsv); - - // NOTE: Vector3ToColor() only available on raylib 1.8.1 - *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x), - (unsigned char)(255.0f*rgb.y), - (unsigned char)(255.0f*rgb.z), - color->a }; + *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x), (unsigned char)(255.0f*rgb.y), (unsigned char)(255.0f*rgb.z), color->a }; } + return result; } @@ -3805,8 +3997,10 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) #define RAYGUI_COLORBARALPHA_CHECKED_SIZE 10 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; + + float prevAlpha = *alpha; Rectangle selector = { (float)bounds.x + (*alpha)*bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.y - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT), @@ -3853,6 +4047,8 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) else state = STATE_FOCUSED; } } + + if (prevAlpha != *alpha) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3893,8 +4089,10 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) // float GuiColorBarLuminance() [BLACK->WHITE] int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; + + float prevHue = *hue; Rectangle selector = { (float)bounds.x - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)bounds.y + (*hue)/360.0f*bounds.height - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2, (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT) }; // Update control @@ -3949,6 +4147,8 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) }*/ } } + + if (prevHue != *hue) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3956,15 +4156,32 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) if (state != STATE_DISABLED) { // Draw hue bar:color bars - // TODO: Use directly DrawRectangleGradientEx(bounds, color1, color2, color2, color1); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + bounds.height/6), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 2*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 3*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 4*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 5*(bounds.height/6)), (int)bounds.width, (int)(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha)); + // NOTE: Using DrawRectangleGradientEx(bounds, color1, color2, color2, color1); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 1*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 2*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 3*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 4*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 5*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha)); + } + else + { + DrawRectangleGradientEx(bounds, + Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), + Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha)); } - else DrawRectangleGradientV((int)bounds.x, (int)bounds.y, (int)bounds.width, (int)bounds.height, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha)); GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); @@ -3984,12 +4201,12 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) // NOTE: this picker converts RGB to HSV, which can cause the Hue control to jump. If you have this problem, consider using the HSV variant instead int GuiColorPicker(Rectangle bounds, const char *text, Color *color) { - int result = 0; + int result = RESULT_NONE; Color temp = { 200, 0, 0, 255 }; if (color == NULL) color = &temp; - GuiColorPanel(bounds, NULL, color); + result = GuiColorPanel(bounds, NULL, color); Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; //Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) }; @@ -3997,7 +4214,7 @@ int GuiColorPicker(Rectangle bounds, const char *text, Color *color) // NOTE: this conversion can cause low hue-resolution, if the r, g and b value are very similar, which causes the hue bar to shift around when only the GuiColorPanel is used Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ (*color).r/255.0f, (*color).g/255.0f, (*color).b/255.0f }); - GuiColorBarHue(boundsHue, NULL, &hsv.x); + if (result != RESULT_CHANGED) result = GuiColorBarHue(boundsHue, NULL, &hsv.x); //color.a = (unsigned char)(GuiColorBarAlpha(boundsAlpha, (float)color.a/255.0f)*255.0f); Vector3 rgb = ConvertHSVtoRGB(hsv); @@ -4016,7 +4233,7 @@ int GuiColorPicker(Rectangle bounds, const char *text, Color *color) // NOTE: bounds define GuiColorPanelHSV() size int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) { - int result = 0; + int result = RESULT_NONE; Vector3 tempHsv = { 0 }; @@ -4027,11 +4244,11 @@ int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) colorHsv = &tempHsv; } - GuiColorPanelHSV(bounds, NULL, colorHsv); + result = GuiColorPanelHSV(bounds, NULL, colorHsv); - const Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; + Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; - GuiColorBarHue(boundsHue, NULL, &colorHsv->x); + if (result == RESULT_NONE) result = GuiColorBarHue(boundsHue, NULL, &colorHsv->x); return result; } @@ -4039,10 +4256,11 @@ int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) // Color Panel control - HSV variant int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; - Vector2 pickerSelector = { 0 }; + Vector3 prevColorHsv = *colorHsv; + Vector2 pickerSelector = { 0 }; const Color colWhite = { 255, 255, 255, 255 }; const Color colBlack = { 0, 0, 0, 255 }; @@ -4051,9 +4269,7 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) Vector3 maxHue = { colorHsv->x, 1.0f, 1.0f }; Vector3 rgbHue = ConvertHSVtoRGB(maxHue); - Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x), - (unsigned char)(255.0f*rgbHue.y), - (unsigned char)(255.0f*rgbHue.z), 255 }; + Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x), (unsigned char)(255.0f*rgbHue.y), (unsigned char)(255.0f*rgbHue.z), 255 }; // Update control //-------------------------------------------------------------------- @@ -4077,12 +4293,11 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) // Calculate color from picker Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y }; - colorPick.x /= (float)bounds.width; // Get normalized value on x - colorPick.y /= (float)bounds.height; // Get normalized value on y + colorPick.x /= (float)bounds.width; // Get normalized value on x + colorPick.y /= (float)bounds.height; // Get normalized value on y colorHsv->y = colorPick.x; colorHsv->z = 1.0f - colorPick.y; - } } else @@ -4112,6 +4327,10 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) else state = STATE_FOCUSED; } } + + if ((prevColorHsv.x != colorHsv->x) || + (prevColorHsv.y != colorHsv->y) || + (prevColorHsv.z != colorHsv->z)) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -4137,7 +4356,8 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) } // Message Box control -int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons) +// NOTE: Button pressed is returned through btnActive parameter, 0 for window close button +int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *btnText, int *btnActive) { #if !defined(RAYGUI_MESSAGEBOX_BUTTON_HEIGHT) #define RAYGUI_MESSAGEBOX_BUTTON_HEIGHT 24 @@ -4146,10 +4366,10 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons #define RAYGUI_MESSAGEBOX_BUTTON_PADDING 12 #endif - int result = -1; // Returns clicked button from buttons list, 0 refers to closed window button + int result = RESULT_NONE; int buttonCount = 0; - char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL); + char **btnTextList = GuiTextSplit(btnText, ';', &buttonCount); Rectangle buttonBounds = { 0 }; buttonBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING; buttonBounds.y = bounds.y + bounds.height - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT - RAYGUI_MESSAGEBOX_BUTTON_PADDING; @@ -4166,7 +4386,11 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons // Draw control //-------------------------------------------------------------------- - if (GuiWindowBox(bounds, title)) result = 0; + if (GuiWindowBox(bounds, title) == RESULT_PRESSED) + { + *btnActive = 0; + result = RESULT_PRESSED; + } int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); @@ -4178,7 +4402,11 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons for (int i = 0; i < buttonCount; i++) { - if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1; + if (GuiButton(buttonBounds, btnTextList[i])) + { + *btnActive = i + 1; + result = RESULT_PRESSED; + } buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING); } @@ -4188,8 +4416,9 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons return result; } -// Text Input Box control, ask for text -int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive) +// Text Input Box control +// NOTE: Button pressed is returned through btnActive parameter, 0 for window close button +int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, char *text, int textSize, const char *btnText, int *btnActive, bool *secretViewActive) { #if !defined(RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT) #define RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT 24 @@ -4201,14 +4430,14 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co #define RAYGUI_TEXTINPUTBOX_HEIGHT 26 #endif + int result = RESULT_NONE; + // Used to enable text edit mode // WARNING: No more than one GuiTextInputBox() should be open at the same time static bool textEditMode = false; - int result = -1; - int buttonCount = 0; - char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL); + char **btnTextList = GuiTextSplit(btnText, ';', &buttonCount); Rectangle buttonBounds = { 0 }; buttonBounds.x = bounds.x + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; buttonBounds.y = bounds.y + bounds.height - RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; @@ -4238,7 +4467,11 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co // Draw control //-------------------------------------------------------------------- - if (GuiWindowBox(bounds, title)) result = 0; + if (GuiWindowBox(bounds, title) == RESULT_PRESSED) + { + *btnActive = 0; + result = RESULT_PRESSED; + } // Draw message if available if (message != NULL) @@ -4256,13 +4489,20 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co { static char stars[] = "****************"; if (GuiTextBox(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x, textBoxBounds.y, textBoxBounds.width - 4 - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.height }, - ((*secretViewActive == 1) || textEditMode)? text : stars, textMaxSize, textEditMode)) textEditMode = !textEditMode; + ((*secretViewActive == 1) || textEditMode)? text : stars, textSize, textEditMode) == RESULT_PRESSED) textEditMode = !textEditMode; - GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, (*secretViewActive == 1)? "#44#" : "#45#", secretViewActive); +#if defined(RAYGUI_NO_ICONS) + GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, + (*secretViewActive == 1)? "O" : "*", secretViewActive); +#else + GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, + (*secretViewActive == 1)? GuiIconText(ICON_EYE_ON, NULL) : GuiIconText(ICON_EYE_OFF, NULL), secretViewActive); +#endif } else { - if (GuiTextBox(textBoxBounds, text, textMaxSize, textEditMode)) textEditMode = !textEditMode; + if (GuiTextBox(textBoxBounds, text, textSize, textEditMode) == RESULT_PRESSED) + textEditMode = !textEditMode; } GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, prevTextBoxAlignment); @@ -4272,16 +4512,21 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co for (int i = 0; i < buttonCount; i++) { - if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1; + if (GuiButton(buttonBounds, btnTextList[i])) + { + *btnActive = i + 1; + result = RESULT_PRESSED; + } + buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING); } - if (result >= 0) textEditMode = false; + if (result == RESULT_PRESSED) textEditMode = false; GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevBtnTextAlignment); //-------------------------------------------------------------------- - return result; // Result is the pressed button index + return result; } // Grid control @@ -4295,7 +4540,7 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect #define RAYGUI_GRID_ALPHA 0.15f #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; Vector2 mousePoint = GUI_POINTER_POSITION; @@ -4316,6 +4561,8 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect // NOTE: Cell values must be the upper left of the cell the mouse is in currentMouseCell.x = floorf((mousePoint.x - bounds.x)/spacing); currentMouseCell.y = floorf((mousePoint.y - bounds.y)/spacing); + + result = RESULT_PRESSED; } } //-------------------------------------------------------------------- @@ -4342,6 +4589,7 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect } if (mouseCell != NULL) *mouseCell = currentMouseCell; + return result; } @@ -4385,11 +4633,16 @@ void GuiLoadStyle(const char *fileName) int controlId = 0; int propertyId = 0; unsigned int propertyValue = 0; + unsigned int version = 0; while (!feof(rgsFile)) { switch (buffer[0]) { + case 'v': + { + sscanf(buffer, "v %d", &version); + } case 'p': { // Style property: p @@ -4400,12 +4653,17 @@ void GuiLoadStyle(const char *fileName) } break; case 'f': { - // Style font: f + // Style font: f int fontSize = 0; - char charmapFileName[256] = { 0 }; - char fontFileName[256] = { 0 }; - sscanf(buffer, "f %d %s %[^\r\n]s", &fontSize, charmapFileName, fontFileName); + char charmapFileName[32] = { 0 }; + char fontFileName[32] = { 0 }; + + if (version >= 600) sscanf(buffer, "f %d %31s %31[^\r\n]s", &fontSize, fontFileName, charmapFileName); + else sscanf(buffer, "f %d %31s %31[^\r\n]s", &fontSize, charmapFileName, fontFileName); + + // GLOBAL: Copy font file name into guiFontName + snprintf(guiFontName, 32, "%s", fontFileName); Font font = { 0 }; int *codepoints = NULL; @@ -4481,6 +4739,318 @@ void GuiLoadStyle(const char *fileName) } } +// Load style from memory +// WARNING: Binary files only +void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize) +{ + // Style File Structure (.rgs) + // ------------------------------------------------------ + // Offset | Size | Type | Description + // ------------------------------------------------------ + // 0 | 4 | char | Signature: "rGS " + // 4 | 2 | short | Version: 200, 400, 600 + // 6 | 2 | short | reserved + // 8 | 4 | int | Num properties (only changed ones from default style) + + // Properties Data (8 bytes per property) + // WARNING: Only properties required that differ from default (light) internal style + // foreach (property) + // { + // 8+8*i | 2 | short | ControlId + // 8+8*i | 2 | short | PropertyId + // 8+8*i | 4 | int | PropertyValue + // } + + // Custom Font Data : Parameters (64 bytes) + // ... | 4 | int | Font data size (0 - no font, no more fields added!) + // ... | 32 | char | Font filename (with extension) - VERSION: >=600 + // ... | 4 | int | Font base size + // ... | 4 | int | Font glyph count [glyphCount] + // ... | 4 | int | Font type (0-NORMAL, 1-SDF) + // ... | 16 | Rectangle | Font white rectangle + + // Custom Font Data : Image (20 bytes + imData) + // NOTE: Font image atlas is always converted to GRAY+ALPHA + // and atlas image data can be compressed (DEFLATE) + // ... | 4 | int | Image data size (uncompressed) + // ... | 4 | int | Image data size (compressed) + // ... | 4 | int | Image width + // ... | 4 | int | Image height + // ... | 4 | int | Image format: GRAY+ALPHA (expected) + // ... | imSize | byte | Image data (comp or uncomp) + + // Custom Font Data : Recs (32 bytes*glyphCount) + // NOTE: Font recs data can be compressed (DEFLATE) + // ... | 4 | int | Recs data compressed size (0 - not compressed, 1-compressed) - VERSION: >=400 + // + // if (compRecsSize == 0) + // { + // NOTE: Uncompressed size can be calculated: (glyphCount*16 byte) + // foreach (glyph) + // { + // ... | 16 | Rectangle | Glyph rectangle (in image) + // } + // } + // else + // { + // ... | compRecsSize | byte | Rectangles data + // } + // + + // Custom Font Data : Glyph Info (32 bytes*glyphCount) + // NOTE: Font glyphs info data can be compressed (DEFLATE) + // ... | 4 | int | Glyphs data compressed size (0 - not compressed) - VERSION: >=400 + // + // if (compGlyphsSize == 0) + // { + // NOTE: Uncompressed size can be calculated: (glyphCount*16 byte) + // foreach (glyph) + // { + // ... | 4 | int | Glyph value + // ... | 4 | int | Glyph offset X + // ... | 4 | int | Glyph offset Y + // ... | 4 | int | Glyph advance X + // } + // } + // else + // { + // ... | compGlyphsSize | byte | Glyphs data + // } + // ------------------------------------------------------ + + unsigned char *fileDataPtr = (unsigned char *)fileData; + + char signature[5] = { 0 }; + short version = 0; + short reserved = 0; + int propertyCount = 0; + + memcpy(signature, fileDataPtr, 4); + memcpy(&version, fileDataPtr + 4, sizeof(short)); + memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short)); + memcpy(&propertyCount, fileDataPtr + 4 + 2 + 2, sizeof(int)); + fileDataPtr += 12; + + if ((signature[0] == 'r') && + (signature[1] == 'G') && + (signature[2] == 'S') && + (signature[3] == ' ')) + { + short controlId = 0; + short propertyId = 0; + unsigned int propertyValue = 0; + + for (int i = 0; i < propertyCount; i++) + { + memcpy(&controlId, fileDataPtr, sizeof(short)); + memcpy(&propertyId, fileDataPtr + 2, sizeof(short)); + memcpy(&propertyValue, fileDataPtr + 2 + 2, sizeof(unsigned int)); + fileDataPtr += 8; + + if (controlId == 0) // DEFAULT control + { + // If a DEFAULT property is loaded, it is propagated to all controls + // NOTE: All DEFAULT properties should be defined first in the file + GuiSetStyle(0, (int)propertyId, propertyValue); + + if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int j = 1; j < RAYGUI_MAX_CONTROLS; j++) GuiSetStyle(j, (int)propertyId, propertyValue); + } + else GuiSetStyle((int)controlId, (int)propertyId, propertyValue); + } + + // Load custom font if available + // NOTE: Font texture loading requires raylib + int fontDataSize = 0; + memcpy(&fontDataSize, fileDataPtr, sizeof(int)); + fileDataPtr += 4; + + if (fontDataSize > 0) + { + Font font = { 0 }; + int fontType = 0; // 0-Normal, 1-SDF + + // WARNING: Version 600 adds 32 bytes for the font filename (with extension) + if (version >= 600) + { + // GLOBAL: Copy font file name into guiFontName + memcpy(guiFontName, fileDataPtr, 32); + fileDataPtr += 32; + } + else memset(guiFontName, 0, 32); + + memcpy(&font.baseSize, fileDataPtr, sizeof(int)); + memcpy(&font.glyphCount, fileDataPtr + 4, sizeof(int)); + memcpy(&fontType, fileDataPtr + 4 + 4, sizeof(int)); + fileDataPtr += 12; + + // Load font white rectangle + Rectangle fontWhiteRec = { 0 }; + memcpy(&fontWhiteRec, fileDataPtr, sizeof(Rectangle)); + fileDataPtr += 16; + + // Load font image parameters + int fontImageUncompSize = 0; + int fontImageCompSize = 0; + memcpy(&fontImageUncompSize, fileDataPtr, sizeof(int)); + memcpy(&fontImageCompSize, fileDataPtr + 4, sizeof(int)); + fileDataPtr += 8; + + Image imFont = { 0 }; + imFont.mipmaps = 1; + memcpy(&imFont.width, fileDataPtr, sizeof(int)); + memcpy(&imFont.height, fileDataPtr + 4, sizeof(int)); + memcpy(&imFont.format, fileDataPtr + 4 + 4, sizeof(int)); + fileDataPtr += 12; + + if ((fontImageCompSize > 0) && (fontImageCompSize != fontImageUncompSize)) + { + // Compressed font atlas image data (DEFLATE), it requires DecompressData() + int dataUncompSize = 0; + unsigned char *compData = (unsigned char *)RAYGUI_CALLOC(fontImageCompSize, sizeof(unsigned char)); + memcpy(compData, fileDataPtr, fontImageCompSize); + fileDataPtr += fontImageCompSize; + + imFont.data = DecompressData(compData, fontImageCompSize, &dataUncompSize); + + // Security check, dataUncompSize must match the provided fontImageUncompSize + if (dataUncompSize != fontImageUncompSize) RAYGUI_LOG("WARNING: Uncompressed font atlas image data could be corrupted"); + + RAYGUI_FREE(compData); + } + else + { + // Font atlas image data is not compressed + imFont.data = (unsigned char *)RAYGUI_CALLOC(fontImageUncompSize, sizeof(unsigned char)); + memcpy(imFont.data, fileDataPtr, fontImageUncompSize); + fileDataPtr += fontImageUncompSize; + } + + // Load font recs data (glyphs position and size in the image atlas) + int recsDataSize = font.glyphCount*sizeof(Rectangle); + int recsDataCompressedSize = 0; + + // WARNING: Version 400 adds the compression size parameter + if (version >= 400) + { + // RGS files version 400 support compressed recs data + memcpy(&recsDataCompressedSize, fileDataPtr, sizeof(int)); + fileDataPtr += sizeof(int); + } + + if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize)) + { + // Recs data is compressed, uncompress it + unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_CALLOC(recsDataCompressedSize, sizeof(unsigned char)); + + memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize); + fileDataPtr += recsDataCompressedSize; + + int recsDataUncompSize = 0; + font.recs = (Rectangle *)DecompressData(recsDataCompressed, recsDataCompressedSize, &recsDataUncompSize); + + // Security check, data uncompressed size must match the expected original data size + if (recsDataUncompSize != recsDataSize) RAYGUI_LOG("WARNING: Uncompressed font recs data could be corrupted"); + + RAYGUI_FREE(recsDataCompressed); + } + else + { + // Recs data is uncompressed + font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle)); + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.recs[i], fileDataPtr, sizeof(Rectangle)); + fileDataPtr += sizeof(Rectangle); + } + } + + // Load font glyphs info data + int glyphsDataSize = font.glyphCount*16; // 16 bytes data per glyph + int glyphsDataCompressedSize = 0; + + // WARNING: Version 400 adds the compression size parameter + if (version >= 400) + { + // RGS files version 400 support compressed glyphs data + memcpy(&glyphsDataCompressedSize, fileDataPtr, sizeof(int)); + fileDataPtr += sizeof(int); + } + + // Allocate required glyphs space to fill with data + font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo)); + + if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize)) + { + // Glyphs data is compressed, uncompress it + unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_CALLOC(glyphsDataCompressedSize, sizeof(unsigned char)); + + memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize); + fileDataPtr += glyphsDataCompressedSize; + + int glyphsDataUncompSize = 0; + unsigned char *glyphsDataUncomp = DecompressData(glypsDataCompressed, glyphsDataCompressedSize, &glyphsDataUncompSize); + + // Security check, data uncompressed size must match the expected original data size + if (glyphsDataUncompSize != glyphsDataSize) RAYGUI_LOG("WARNING: Uncompressed font glyphs data could be corrupted"); + + unsigned char *glyphsDataUncompPtr = glyphsDataUncomp; + + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.glyphs[i].value, glyphsDataUncompPtr, sizeof(int)); + memcpy(&font.glyphs[i].offsetX, glyphsDataUncompPtr + 4, sizeof(int)); + memcpy(&font.glyphs[i].offsetY, glyphsDataUncompPtr + 8, sizeof(int)); + memcpy(&font.glyphs[i].advanceX, glyphsDataUncompPtr + 12, sizeof(int)); + glyphsDataUncompPtr += 16; + } + + RAYGUI_FREE(glypsDataCompressed); + RAYGUI_FREE(glyphsDataUncomp); + } + else + { + // Glyphs data is uncompressed + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.glyphs[i].value, fileDataPtr, sizeof(int)); + memcpy(&font.glyphs[i].offsetX, fileDataPtr + 4, sizeof(int)); + memcpy(&font.glyphs[i].offsetY, fileDataPtr + 8, sizeof(int)); + memcpy(&font.glyphs[i].advanceX, fileDataPtr + 12, sizeof(int)); + fileDataPtr += 16; + } + } + +#if defined(RAYGUI_FONT_ICONS_BAKING) + // Font atlas image icons baking + Rectangle updatedWhiteRec = { 0 }; + guiIconFontOffsetY = GuiFontIconBaking(&imFont, font, &updatedWhiteRec); + if (guiIconFontOffsetY > 0) fontWhiteRec = updatedWhiteRec; +#endif + +#if !defined(RAYGUI_STANDALONE) + // Load texture from image + if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture); + font.texture = LoadTextureFromImage(imFont); + + // Fallback to default raylib texture if font texture loading fails + if (font.texture.id != 0) + { + // Set font texture source rectangle to be used as white texture to draw shapes + // NOTE: It makes possible to draw shapes and text (full UI) in a single draw call + if ((fontWhiteRec.x > 0) && + (fontWhiteRec.y > 0) && + (fontWhiteRec.width > 0) && + (fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec); + } + else font = GetFontDefault(); + + GuiSetFont(font); +#endif + RAYGUI_FREE(imFont.data); + } + } +} + // Load style default over global style void GuiLoadStyleDefault(void) { @@ -4513,7 +5083,7 @@ void GuiLoadStyleDefault(void) GuiSetStyle(DEFAULT, TEXT_SPACING, 1); // DEFAULT, shared by all controls GuiSetStyle(DEFAULT, LINE_COLOR, 0x90abb5ff); // DEFAULT specific property GuiSetStyle(DEFAULT, BACKGROUND_COLOR, 0xf5f5f5ff); // DEFAULT specific property - GuiSetStyle(DEFAULT, TEXT_LINE_SPACING, 5); // DEFAULT, pixels between lines, from bottom of first line to top of second + GuiSetStyle(DEFAULT, TEXT_LINE_SPACING, 12); // DEFAULT, pixels between lines, from bottom of first line to top of second GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); // DEFAULT, text aligned vertically to middle of text-bounds // Initialize control-specific property values @@ -4532,6 +5102,7 @@ void GuiLoadStyleDefault(void) GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); GuiSetStyle(STATUSBAR, TEXT_PADDING, 8); GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(TABBAR, TAB_ITEMS_WIDTH, 160); // Initialize extended property values // NOTE: By default, extended property values are initialized to 0 @@ -4581,6 +5152,9 @@ void GuiLoadStyleDefault(void) // NOTE: Setting up a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering SetShapesTexture(guiFont.texture, RAYGUI_CLITERAL(Rectangle){ whiteChar.x + 1, whiteChar.y + 1, whiteChar.width - 2, whiteChar.height - 2 }); + + // Reset baked icons offset in font + guiIconFontOffsetY = 0; } } @@ -4622,71 +5196,28 @@ const char *GuiIconText(int iconId, const char *text) unsigned int *GuiGetIcons(void) { return guiIconsPtr; } // Load raygui icons file (.rgi) -// NOTE: In case nameIds are required, they can be requested with loadIconsName, -// they are returned as a guiIconsName[iconCount][RAYGUI_ICON_MAX_NAME_LENGTH], // WARNING: guiIconsName[]][] memory should be manually freed! char **GuiLoadIcons(const char *fileName, bool loadIconsName) { - // Style File Structure (.rgi) - // ------------------------------------------------------ - // Offset | Size | Type | Description - // ------------------------------------------------------ - // 0 | 4 | char | Signature: "rGI " - // 4 | 2 | short | Version: 100 - // 6 | 2 | short | reserved - - // 8 | 2 | short | Num icons (N) - // 10 | 2 | short | Icons size (Options: 16, 32, 64) (S) - - // Icons name id (32 bytes per name id) - // foreach (icon) - // { - // 12+32*i | 32 | char | Icon NameId - // } - - // Icons data: One bit per pixel, stored as unsigned int array (depends on icon size) - // S*S pixels/32bit per unsigned int = K unsigned int per icon - // foreach (icon) - // { - // ... | K | unsigned int | Icon Data - // } - FILE *rgiFile = fopen(fileName, "rb"); - char **guiIconsName = NULL; if (rgiFile != NULL) { - char signature[5] = { 0 }; - short version = 0; - short reserved = 0; - short iconCount = 0; - short iconSize = 0; + unsigned char *fileData = NULL; + int dataSize = 0; - fread(signature, 1, 4, rgiFile); - fread(&version, sizeof(short), 1, rgiFile); - fread(&reserved, sizeof(short), 1, rgiFile); - fread(&iconCount, sizeof(short), 1, rgiFile); - fread(&iconSize, sizeof(short), 1, rgiFile); + fseek(rgiFile, 0, SEEK_END); + int size = (int)ftell(rgiFile); + fseek(rgiFile, 0, SEEK_SET); - if ((signature[0] == 'r') && - (signature[1] == 'G') && - (signature[2] == 'I') && - (signature[3] == ' ')) + if (size > 0) { - if (loadIconsName) - { - guiIconsName = (char **)RAYGUI_CALLOC(iconCount, sizeof(char *)); - for (int i = 0; i < iconCount; i++) - { - guiIconsName[i] = (char *)RAYGUI_CALLOC(RAYGUI_ICON_MAX_NAME_LENGTH, sizeof(char)); - fread(guiIconsName[i], 1, RAYGUI_ICON_MAX_NAME_LENGTH, rgiFile); - } - } - else fseek(rgiFile, iconCount*RAYGUI_ICON_MAX_NAME_LENGTH, SEEK_CUR); + fileData = (unsigned char *)RL_CALLOC(size, sizeof(unsigned char)); + // WARNING: File can be partially loaded but ignoring it for simplicity + dataSize = (int)fread(fileData, sizeof(unsigned char), size, rgiFile); - // Read icons data directly over internal icons array - fread(guiIconsPtr, sizeof(unsigned int), (int)iconCount*((int)iconSize*(int)iconSize/32), rgiFile); + guiIconsName = GuiLoadIconsFromMemory(fileData, dataSize, loadIconsName); } fclose(rgiFile); @@ -4696,9 +5227,34 @@ char **GuiLoadIcons(const char *fileName, bool loadIconsName) } // Load icons from memory -// WARNING: Binary files only +// GLOBAL: Updates global variable: guiIconsPtr char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName) { + // Icon File Structure (.rgi) + // ------------------------------------------------------ + // Offset | Size | Type | Description + // ------------------------------------------------------ + // 0 | 4 | char | Signature: "rGI " + // 4 | 2 | short | Version: 100, 500 + // 6 | 2 | short | reserved + + // 8 | 2 | short | Num icons (N) + // 10 | 2 | short | Icons Size (Options: 16, 32, 64) + + // Icons name id (32 bytes per name id) + // foreach (icon) + // { + // 12+32*i | 32 | char | Icon NameId + // } + + // Icons data: One bit per pixel, stored as unsigned int array (depends on icon size) + // Size*Size pixels/32bit per unsigned int = K unsigned int per icon + // foreach (icon) + // { + // ... | K | unsigned int | Icon Data + // } + // ------------------------------------------------------ + unsigned char *fileDataPtr = (unsigned char *)fileData; char **guiIconsName = NULL; @@ -4722,7 +5278,8 @@ char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool { if (loadIconsName) { - guiIconsName = (char **)RAYGUI_CALLOC(iconCount, sizeof(char *)); + // NOTE: Always allocating RAYGUI_ICON_MAX_ICONS names slots + guiIconsName = (char **)RAYGUI_CALLOC(RAYGUI_ICON_MAX_ICONS, sizeof(char *)); for (int i = 0; i < iconCount; i++) { guiIconsName[i] = (char *)RAYGUI_CALLOC(RAYGUI_ICON_MAX_NAME_LENGTH, sizeof(char)); @@ -4748,20 +5305,35 @@ char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool // Draw selected icon using rectangles pixel-by-pixel void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color) { - #define BIT_CHECK(a,b) ((a) & (1u<<(b))) - - for (int i = 0, y = 0; i < RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32; i++) + if ((guiIconFontOffsetY > 0) && (iconId < RAYGUI_ICON_MAX_FONT_BACKED)) { - for (int k = 0; k < 32; k++) - { - if (BIT_CHECK(guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i], k)) - { - #if !defined(RAYGUI_STANDALONE) - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize, (float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color); - #endif - } + int maxIconsPerLine = guiFont.texture.width/(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + int x = iconId%maxIconsPerLine; + int y = iconId/maxIconsPerLine; - if ((k == 15) || (k == 31)) y++; + Rectangle srcRec = { (float)x*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + RAYGUI_ICON_FONT_ATLAS_PADDING, + guiIconFontOffsetY + (float)y*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + RAYGUI_ICON_FONT_ATLAS_PADDING, + RAYGUI_ICON_SIZE, RAYGUI_ICON_SIZE }; + Rectangle dstRec = { (float)posX, (float)posY, (float)pixelSize*RAYGUI_ICON_SIZE, (float)pixelSize*RAYGUI_ICON_SIZE }; + + DrawTexturePro(guiFont.texture, srcRec, dstRec, RAYGUI_CLITERAL(Vector2){ 0, 0 }, 0.0f, color); + } + else + { + #define BIT_CHECK(a,b) ((a) & (1u<<(b))) + + for (int i = 0, y = 0; i < RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32; i++) + { + for (int k = 0; k < 32; k++) + { + if (BIT_CHECK(guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i], k)) + { + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize, + (float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color); + } + + if ((k == 15) || (k == 31)) y++; + } } } } @@ -4772,28 +5344,56 @@ void GuiSetIconScale(int scale) if (scale >= 1) guiIconScale = scale; } -// Get text width considering gui style and icon size (if required) +// Get text width considering gui style and icon size (if required). +// For multi-line text (containing '\n'), returns the width of the widest line. int GuiGetTextWidth(const char *text) { - #if !defined(ICON_TEXT_PADDING) - #define ICON_TEXT_PADDING 4 - #endif + if (text == NULL) return 0; + + int maxWidth = 0; + const char *linePtr = text; + + while ((linePtr[0] != '\0') && ((linePtr - text) < MAX_LINE_BUFFER_SIZE)) + { + int lineWidth = GetLineWidth(linePtr); + if (lineWidth > maxWidth) maxWidth = lineWidth; + + // Skip to the next '\n' (or end of string/buffer) + while ((linePtr[0] != '\0') && (linePtr[0] != '\n') && ((linePtr - text) < MAX_LINE_BUFFER_SIZE)) + { + linePtr++; + } + // Advance past the '\n' delimiter to the start of the next line + if (linePtr[0] == '\n') linePtr++; + } + + return maxWidth; +} + +#endif // !RAYGUI_NO_ICONS + +//---------------------------------------------------------------------------------- +// Module Internal Functions Definition +//---------------------------------------------------------------------------------- +// Get text line width (stops at '\n' or '\0') +// NOTE: Considers icon marker '#NNN#' +static int GetLineWidth(const char *text) +{ +#if !defined(RAYGUI_ICON_TEXT_PADDING) + #define RAYGUI_ICON_TEXT_PADDING 4 +#endif Vector2 textSize = { 0 }; int textIconOffset = 0; if ((text != NULL) && (text[0] != '\0')) { + // Icon marker: '#' + 1..3 digits + '#' (matches GetTextIcon()) if (text[0] == '#') { - for (int i = 1; (i < 5) && (text[i] != '\0'); i++) - { - if (text[i] == '#') - { - textIconOffset = i; - break; - } - } + int pos = 1; + while ((pos < 4) && (text[pos] >= '0') && (text[pos] <= '9')) pos++; + if (text[pos] == '#') textIconOffset = pos + 1; } text += textIconOffset; @@ -4801,10 +5401,10 @@ int GuiGetTextWidth(const char *text) // Make sure guiFont is set, GuiGetStyle() initializes it lazynessly float fontSize = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - // Custom MeasureText() implementation + // Custom MeasureText() implementation -- single line only if ((guiFont.texture.id > 0) && (text != NULL)) { - // Get size in bytes of text, considering end of line and line break + // Get size in bytes of the line, considering end of line and line break int size = 0; for (int i = 0; i < MAX_LINE_BUFFER_SIZE; i++) { @@ -4828,239 +5428,12 @@ int GuiGetTextWidth(const char *text) } } - if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + ICON_TEXT_PADDING); + if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + RAYGUI_ICON_TEXT_PADDING); } return (int)textSize.x; } -#endif // !RAYGUI_NO_ICONS - -//---------------------------------------------------------------------------------- -// Module Internal Functions Definition -//---------------------------------------------------------------------------------- -// Load style from memory -// WARNING: Binary files only -static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize) -{ - unsigned char *fileDataPtr = (unsigned char *)fileData; - - char signature[5] = { 0 }; - short version = 0; - short reserved = 0; - int propertyCount = 0; - - memcpy(signature, fileDataPtr, 4); - memcpy(&version, fileDataPtr + 4, sizeof(short)); - memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short)); - memcpy(&propertyCount, fileDataPtr + 4 + 2 + 2, sizeof(int)); - fileDataPtr += 12; - - if ((signature[0] == 'r') && - (signature[1] == 'G') && - (signature[2] == 'S') && - (signature[3] == ' ')) - { - short controlId = 0; - short propertyId = 0; - unsigned int propertyValue = 0; - - for (int i = 0; i < propertyCount; i++) - { - memcpy(&controlId, fileDataPtr, sizeof(short)); - memcpy(&propertyId, fileDataPtr + 2, sizeof(short)); - memcpy(&propertyValue, fileDataPtr + 2 + 2, sizeof(unsigned int)); - fileDataPtr += 8; - - if (controlId == 0) // DEFAULT control - { - // If a DEFAULT property is loaded, it is propagated to all controls - // NOTE: All DEFAULT properties should be defined first in the file - GuiSetStyle(0, (int)propertyId, propertyValue); - - if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int j = 1; j < RAYGUI_MAX_CONTROLS; j++) GuiSetStyle(j, (int)propertyId, propertyValue); - } - else GuiSetStyle((int)controlId, (int)propertyId, propertyValue); - } - - // Font loading is highly dependant on raylib API to load font data and image - -#if !defined(RAYGUI_STANDALONE) - // Load custom font if available - int fontDataSize = 0; - memcpy(&fontDataSize, fileDataPtr, sizeof(int)); - fileDataPtr += 4; - - if (fontDataSize > 0) - { - Font font = { 0 }; - int fontType = 0; // 0-Normal, 1-SDF - - memcpy(&font.baseSize, fileDataPtr, sizeof(int)); - memcpy(&font.glyphCount, fileDataPtr + 4, sizeof(int)); - memcpy(&fontType, fileDataPtr + 4 + 4, sizeof(int)); - fileDataPtr += 12; - - // Load font white rectangle - Rectangle fontWhiteRec = { 0 }; - memcpy(&fontWhiteRec, fileDataPtr, sizeof(Rectangle)); - fileDataPtr += 16; - - // Load font image parameters - int fontImageUncompSize = 0; - int fontImageCompSize = 0; - memcpy(&fontImageUncompSize, fileDataPtr, sizeof(int)); - memcpy(&fontImageCompSize, fileDataPtr + 4, sizeof(int)); - fileDataPtr += 8; - - Image imFont = { 0 }; - imFont.mipmaps = 1; - memcpy(&imFont.width, fileDataPtr, sizeof(int)); - memcpy(&imFont.height, fileDataPtr + 4, sizeof(int)); - memcpy(&imFont.format, fileDataPtr + 4 + 4, sizeof(int)); - fileDataPtr += 12; - - if ((fontImageCompSize > 0) && (fontImageCompSize != fontImageUncompSize)) - { - // Compressed font atlas image data (DEFLATE), it requires DecompressData() - int dataUncompSize = 0; - unsigned char *compData = (unsigned char *)RAYGUI_CALLOC(fontImageCompSize, sizeof(unsigned char)); - memcpy(compData, fileDataPtr, fontImageCompSize); - fileDataPtr += fontImageCompSize; - - imFont.data = DecompressData(compData, fontImageCompSize, &dataUncompSize); - - // Security check, dataUncompSize must match the provided fontImageUncompSize - if (dataUncompSize != fontImageUncompSize) RAYGUI_LOG("WARNING: Uncompressed font atlas image data could be corrupted"); - - RAYGUI_FREE(compData); - } - else - { - // Font atlas image data is not compressed - imFont.data = (unsigned char *)RAYGUI_CALLOC(fontImageUncompSize, sizeof(unsigned char)); - memcpy(imFont.data, fileDataPtr, fontImageUncompSize); - fileDataPtr += fontImageUncompSize; - } - - if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture); - font.texture = LoadTextureFromImage(imFont); - - RAYGUI_FREE(imFont.data); - - // Validate font atlas texture was loaded correctly - if (font.texture.id != 0) - { - // Load font recs data - int recsDataSize = font.glyphCount*sizeof(Rectangle); - int recsDataCompressedSize = 0; - - // WARNING: Version 400 adds the compression size parameter - if (version >= 400) - { - // RGS files version 400 support compressed recs data - memcpy(&recsDataCompressedSize, fileDataPtr, sizeof(int)); - fileDataPtr += sizeof(int); - } - - if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize)) - { - // Recs data is compressed, uncompress it - unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_CALLOC(recsDataCompressedSize, sizeof(unsigned char)); - - memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize); - fileDataPtr += recsDataCompressedSize; - - int recsDataUncompSize = 0; - font.recs = (Rectangle *)DecompressData(recsDataCompressed, recsDataCompressedSize, &recsDataUncompSize); - - // Security check, data uncompressed size must match the expected original data size - if (recsDataUncompSize != recsDataSize) RAYGUI_LOG("WARNING: Uncompressed font recs data could be corrupted"); - - RAYGUI_FREE(recsDataCompressed); - } - else - { - // Recs data is uncompressed - font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle)); - for (int i = 0; i < font.glyphCount; i++) - { - memcpy(&font.recs[i], fileDataPtr, sizeof(Rectangle)); - fileDataPtr += sizeof(Rectangle); - } - } - - // Load font glyphs info data - int glyphsDataSize = font.glyphCount*16; // 16 bytes data per glyph - int glyphsDataCompressedSize = 0; - - // WARNING: Version 400 adds the compression size parameter - if (version >= 400) - { - // RGS files version 400 support compressed glyphs data - memcpy(&glyphsDataCompressedSize, fileDataPtr, sizeof(int)); - fileDataPtr += sizeof(int); - } - - // Allocate required glyphs space to fill with data - font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo)); - - if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize)) - { - // Glyphs data is compressed, uncompress it - unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_CALLOC(glyphsDataCompressedSize, sizeof(unsigned char)); - - memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize); - fileDataPtr += glyphsDataCompressedSize; - - int glyphsDataUncompSize = 0; - unsigned char *glyphsDataUncomp = DecompressData(glypsDataCompressed, glyphsDataCompressedSize, &glyphsDataUncompSize); - - // Security check, data uncompressed size must match the expected original data size - if (glyphsDataUncompSize != glyphsDataSize) RAYGUI_LOG("WARNING: Uncompressed font glyphs data could be corrupted"); - - unsigned char *glyphsDataUncompPtr = glyphsDataUncomp; - - for (int i = 0; i < font.glyphCount; i++) - { - memcpy(&font.glyphs[i].value, glyphsDataUncompPtr, sizeof(int)); - memcpy(&font.glyphs[i].offsetX, glyphsDataUncompPtr + 4, sizeof(int)); - memcpy(&font.glyphs[i].offsetY, glyphsDataUncompPtr + 8, sizeof(int)); - memcpy(&font.glyphs[i].advanceX, glyphsDataUncompPtr + 12, sizeof(int)); - glyphsDataUncompPtr += 16; - } - - RAYGUI_FREE(glypsDataCompressed); - RAYGUI_FREE(glyphsDataUncomp); - } - else - { - // Glyphs data is uncompressed - for (int i = 0; i < font.glyphCount; i++) - { - memcpy(&font.glyphs[i].value, fileDataPtr, sizeof(int)); - memcpy(&font.glyphs[i].offsetX, fileDataPtr + 4, sizeof(int)); - memcpy(&font.glyphs[i].offsetY, fileDataPtr + 8, sizeof(int)); - memcpy(&font.glyphs[i].advanceX, fileDataPtr + 12, sizeof(int)); - fileDataPtr += 16; - } - } - } - else font = GetFontDefault(); // Fallback in case of errors loading font atlas texture - - GuiSetFont(font); - - // Set font texture source rectangle to be used as white texture to draw shapes - // NOTE: It makes possible to draw shapes and text (full UI) in a single draw call - if ((fontWhiteRec.x > 0) && - (fontWhiteRec.y > 0) && - (fontWhiteRec.width > 0) && - (fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec); - } -#endif - } -} - // Get text bounds considering control bounds static Rectangle GetTextBounds(int control, Rectangle bounds) { @@ -5081,11 +5454,11 @@ static Rectangle GetTextBounds(int control, Rectangle bounds) case SLIDER: case CHECKBOX: case VALUEBOX: - case CONTROL11: - // TODO: More special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER + case TABBAR: + // TODO: Special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER default: { - // TODO: WARNING: TEXT_ALIGNMENT is already considered in GuiDrawText() + // WARNING: TEXT_ALIGNMENT is already considered in GuiDrawText() if (GuiGetStyle(control, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT) textBounds.x -= GuiGetStyle(control, TEXT_PADDING); else textBounds.x += GuiGetStyle(control, TEXT_PADDING); } @@ -5096,12 +5469,12 @@ static Rectangle GetTextBounds(int control, Rectangle bounds) } // Get text icon if provided and move text cursor -// NOTE: Up to #999# values supported for iconId +// NOTE: Up to RAYGUI_ICON_MAX_ICONS supported for iconId static const char *GetTextIcon(const char *text, int *iconId) { #if !defined(RAYGUI_NO_ICONS) *iconId = -1; - if (text[0] == '#') // Maybe it is stars with an icon, ending # must be found + if (text[0] == '#') // Maybe an icon, if it starts with # but an ending # must be found { char iconValue[4] = { 0 }; // Maximum length for icon value: 3 digits + '\0' @@ -5114,11 +5487,15 @@ static const char *GetTextIcon(const char *text, int *iconId) if (text[pos] == '#') { - *iconId = TextToInteger(iconValue); + int rawIconId = TextToInteger(iconValue); + if (rawIconId < RAYGUI_ICON_MAX_ICONS) + { + *iconId = rawIconId; - // Move text pointer after icon - // WARNING: If only icon provided, it could point to EOL character: '\0' - if (*iconId >= 0) text += (pos + 1); + // Move text pointer after icon + // WARNING: If only icon provided, it could point to EOL character: '\0' + if (*iconId >= 0) text += (pos + 1); + } } } #endif @@ -5186,8 +5563,8 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C { #define TEXT_VALIGN_PIXEL_OFFSET(h) ((int)h%2) // Vertical alignment for pixel perfect - #if !defined(ICON_TEXT_PADDING) - #define ICON_TEXT_PADDING 4 + #if !defined(RAYGUI_ICON_TEXT_PADDING) + #define RAYGUI_ICON_TEXT_PADDING 4 #endif if ((text == NULL) || (text[0] == '\0')) return; // Security check @@ -5223,9 +5600,9 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C Vector2 textBoundsPosition = { textBounds.x, textBounds.y }; float textBoundsWidthOffset = 0.0f; - // NOTE: Get text size after icon has been processed - // WARNING: GuiGetTextWidth() also processes text icon to get width! -> Really needed? - int textSizeX = GuiGetTextWidth(lines[i]); + // NOTE: Icon was already stripped above by GetTextIcon(); GetLineWidth() + // takes no icon path here and returns only the glyph width of this line. + int textSizeX = GetLineWidth(lines[i]); // If text requires an icon, add size to measure if (iconId >= 0) @@ -5234,7 +5611,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C // WARNING: If only icon provided, text could be pointing to EOF character: '\0' #if !defined(RAYGUI_NO_ICONS) - if ((lines[i] != NULL) && (lines[i][0] != '\0')) textSizeX += ICON_TEXT_PADDING; + if ((lines[i] != NULL) && (lines[i][0] != '\0')) textSizeX += RAYGUI_ICON_TEXT_PADDING; #endif } @@ -5271,12 +5648,11 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C { // NOTE: Considering icon height, probably different than text size GuiDrawIcon(iconId, (int)textBoundsPosition.x, (int)(textBounds.y + textBounds.height/2 - RAYGUI_ICON_SIZE*guiIconScale/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height)), guiIconScale, tint); - textBoundsPosition.x += (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); - textBoundsWidthOffset = (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); + textBoundsPosition.x += (float)(RAYGUI_ICON_SIZE*guiIconScale + RAYGUI_ICON_TEXT_PADDING); + textBoundsWidthOffset = (float)(RAYGUI_ICON_SIZE*guiIconScale + RAYGUI_ICON_TEXT_PADDING); } #endif - // Get size in bytes of text, - // considering end of line and line break + // Get size in bytes of text, considering end of line and line break int lineSize = 0; for (int c = 0; (lines[i][c] != '\0') && (lines[i][c] != '\n') && (lines[i][c] != '\r'); c++, lineSize++){ } float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize; @@ -5297,7 +5673,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C // NOTE: Normally, exiting the decoding sequence as soon as a bad byte is found (and return 0x3f) // but all of the bad bytes need to be drawn using the '?' symbol, moving one byte - if (codepoint == 0x3f) codepointSize = 1; // TODO: Review not recognized codepoints size + if (codepoint == 0x3f) codepointSize = 1; // WARNING: Not recognized codepoints size // Get glyph width to check if it goes out of bounds if (guiFont.glyphs[index].advanceX == 0) glyphWidth = ((float)guiFont.recs[index].width*scaleFactor); @@ -5313,7 +5689,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C textOffsetX = 0.0f; textOffsetY += (GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); - if (tempWrapCharMode) // Wrap at char level when too long words + if (tempWrapCharMode) // Wrap at char level when too long words { wrapMode = TEXT_WRAP_WORD; tempWrapCharMode = false; @@ -5344,12 +5720,12 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C } } - if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint + if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint else { - // TODO: There are multiple types of spaces in Unicode, + // WARNING: There are multiple types of spaces in Unicode, // maybe it's a good idea to add support for more: http://jkorpela.fi/chars/spaces.html - if ((codepoint != ' ') && (codepoint != '\t')) // Do not draw codepoints with no glyph + if ((codepoint != ' ') && (codepoint != '\t')) // Do not draw codepoints with no glyph { if (wrapMode == TEXT_WRAP_NONE) { @@ -5391,7 +5767,8 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C } if (wrapMode == TEXT_WRAP_NONE) posOffsetY += (float)(GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); - else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) posOffsetY += (textOffsetY + (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); + else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) + posOffsetY += (textOffsetY + GuiGetStyle(DEFAULT, TEXT_SIZE)); //--------------------------------------------------------------------------------- } @@ -5428,7 +5805,8 @@ static void GuiTooltip(Rectangle controlRec) { if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiControlExclusiveMode) { - Vector2 textSize = MeasureTextEx(GuiGetFont(), guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + Vector2 textSize = MeasureTextEx(guiFont, guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); if ((controlRec.x + textSize.x + 16) > GetScreenWidth()) controlRec.x -= (textSize.x + 16 - controlRec.width); @@ -5450,9 +5828,264 @@ static void GuiTooltip(Rectangle controlRec) } } +// Scroll bar control (used by GuiScrollPanel()) +static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) +{ + GuiState state = guiState; + + // Is the scrollbar horizontal or vertical? + bool isVertical = (bounds.width > bounds.height)? false : true; + + // The size (width or height depending on scrollbar type) of the spinner buttons + const int spinnerSize = GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)? + (isVertical? (int)bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) : + (int)bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0; + + // Arrow buttons [<] [>] [∧] [∨] + Rectangle arrowUpLeft = { 0 }; + Rectangle arrowDownRight = { 0 }; + + // Actual area of the scrollbar excluding the arrow buttons + Rectangle scrollbar = { 0 }; + + // Slider bar that moves --[///]----- + Rectangle slider = { 0 }; + + // Normalize value + if (value > maxValue) value = maxValue; + if (value < minValue) value = minValue; + + int valueRange = maxValue - minValue; + if (valueRange <= 0) valueRange = 1; + + int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); + if (sliderSize < 1) sliderSize = 1; // Consider a minimum slider size of 1 pixel + + // Calculate rectangles for all of the components + arrowUpLeft = RAYGUI_CLITERAL(Rectangle){ + (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), + (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), + (float)spinnerSize, (float)spinnerSize }; + + if (isVertical) + { + arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + bounds.height - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; + scrollbar = RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), arrowUpLeft.y + arrowUpLeft.height, bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)), bounds.height - arrowUpLeft.height - arrowDownRight.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) }; + + // Make sure the slider won't get outside of the scrollbar + sliderSize = (sliderSize >= scrollbar.height)? ((int)scrollbar.height - 2) : sliderSize; + slider = RAYGUI_CLITERAL(Rectangle){ + bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), + scrollbar.y + (int)(((float)(value - minValue)/valueRange)*(scrollbar.height - sliderSize)), + bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)), + (float)sliderSize }; + } + else // horizontal + { + arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; + scrollbar = RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x + arrowUpLeft.width, bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), bounds.width - arrowUpLeft.width - arrowDownRight.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)) }; + + // Make sure the slider won't get outside of the scrollbar + sliderSize = (sliderSize >= scrollbar.width)? ((int)scrollbar.width - 2) : sliderSize; + slider = RAYGUI_CLITERAL(Rectangle){ + scrollbar.x + (int)(((float)(value - minValue)/valueRange)*(scrollbar.width - sliderSize)), + bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), + (float)sliderSize, + bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)) }; + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (GUI_BUTTON_DOWN && + !CheckCollisionPointRec(mousePoint, arrowUpLeft) && + !CheckCollisionPointRec(mousePoint, arrowDownRight)) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + state = STATE_PRESSED; + + if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); + else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + + // Handle mouse wheel + float scrollDelta = GUI_SCROLL_DELTA; + if (scrollDelta != 0) value += (int)scrollDelta; + + // Handle mouse button down + if (GUI_BUTTON_PRESSED) + { + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + + // Check arrows click + if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + else if (!CheckCollisionPointRec(mousePoint, slider)) + { + // If click on scrollbar position but not on slider, place slider directly on that position + if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); + else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); + } + + state = STATE_PRESSED; + } + + // Keyboard control on mouse hover scrollbar + /* + if (isVertical) + { + if (GUI_KEY_DOWN(KEY_DOWN)) value += 5; + else if (GUI_KEY_DOWN(KEY_UP)) value -= 5; + } + else + { + if (GUI_KEY_DOWN(KEY_RIGHT)) value += 5; + else if (GUI_KEY_DOWN(KEY_LEFT)) value -= 5; + } + */ + } + + // Normalize value + if (value > maxValue) value = maxValue; + if (value < minValue) value = minValue; + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED))); // Draw the background + + GuiDrawRectangle(scrollbar, 0, BLANK, GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL))); // Draw the scrollbar active area background + GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BORDER + state*3))); // Draw the slider bar + + // Draw arrows (using icon if available) + if (GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)) + { +#if defined(RAYGUI_NO_ICONS) + GuiDrawText(isVertical? "^" : "<", + RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); + GuiDrawText(isVertical? "v" : ">", + RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); +#else + GuiDrawText(isVertical? GuiIconText(ICON_ARROW_UP_FILL, NULL) : GuiIconText(ICON_ARROW_LEFT_FILL, NULL), + RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_UP_FILL / ICON_ARROW_LEFT_FILL + GuiDrawText(isVertical? GuiIconText(ICON_ARROW_DOWN_FILL, NULL) : GuiIconText(ICON_ARROW_RIGHT_FILL, NULL), + RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_DOWN_FILL / ICON_ARROW_RIGHT_FILL +#endif + } + //-------------------------------------------------------------------- + + return value; +} + +// Update font image atlas to append raygui icons +static int GuiFontIconBaking(Image *imFont, Font font, Rectangle *whiteRec) +{ + int iconOffsetY = 0; + + // Check max glyph rec y bottom position in the atlas image, + // to start drawing icons below that line + int maxGlyphRecY = 0; + for (int i = 0; i < font.glyphCount; i++) + { + if ((font.recs[i].y + font.recs[i].height) > maxGlyphRecY) + maxGlyphRecY = (int)font.recs[i].y + (int)font.recs[i].height; + } + + int maxIconsPerLine = imFont->width/(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + int reqIconLines = RAYGUI_ICON_MAX_FONT_BACKED/maxIconsPerLine + RAYGUI_ICON_MAX_FONT_BACKED%maxIconsPerLine + 1; // One extra line + int reqHeight = reqIconLines*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + + // Check if image requires scaling and how much + if ((maxGlyphRecY + reqHeight) > imFont->height) + { + int newImHeight = 1; + while (newImHeight < (maxGlyphRecY + reqHeight)) newImHeight <<= 1; // Round to next POT + + char *newImData = (char *)RL_CALLOC(imFont->width*newImHeight*2, sizeof(char)); + memcpy(newImData, imFont->data, imFont->width*imFont->height*2); + RL_FREE(imFont->data); + + // Clear imFont bottom-right corner rec + for (int y = 0; y < 4; y++) + for (int x = 0; x < 4; x++) + ((unsigned short *)newImData)[(imFont->height - y - 1)*imFont->width + imFont->width - x - 1] = 0x0000; + + imFont->data = newImData; + imFont->height = newImHeight; + + // Set new image white corner and new white rec + for (int y = 0; y < 3; y++) + for (int x = 0; x < 3; x++) + ((unsigned short *)newImData)[(imFont->height - y - 1)*imFont->width + imFont->width - x - 1] = 0xffff; + + *whiteRec = RAYGUI_CLITERAL(Rectangle){ (float)imFont->width - 2, (float)imFont->height - 2, 1, 1 }; + } + + // Calculate image offset positions to start drawing + // NOTE: For Y, look for a multiple of icon size + 2*padding, for better alignment + int offsetX = RAYGUI_ICON_FONT_ATLAS_PADDING; + int offsetY = ((maxGlyphRecY + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING - 1))/ + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING))*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + + RAYGUI_ICON_FONT_ATLAS_PADDING; + + iconOffsetY = offsetY - RAYGUI_ICON_FONT_ATLAS_PADDING; + unsigned short *pixels = (unsigned short *)imFont->data; + + #define BIT_CHECK(a,b) ((a) & (1u<<(b))) + + for (int iconId = 0; iconId < RAYGUI_ICON_MAX_FONT_BACKED; iconId++) + { + // Wrap to next line if next icon won't fit + if ((offsetX + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING)) > imFont->width) + { + offsetX = RAYGUI_ICON_FONT_ATLAS_PADDING; + offsetY += RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING; + } + + for (int i = 0, y = 0; i < RAYGUI_ICON_DATA_ELEMENTS; i++) + { + unsigned int data = guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i]; + + for (int k = 0; k < 32; k++) + { + pixels[(offsetY + y)*imFont->width + offsetX + k%16] = (BIT_CHECK(data, k))? 0xffff : 0x00ff; + + if ((k == 15) || (k == 31)) y++; + } + } + + // Update current icon X position + offsetX += (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + } + + return iconOffsetY; +} + // Split controls text into multiple strings -// Also check for multiple columns (required by GuiToggleGroup()) -static char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow) +// NOTE: Re-used by GuiToggleSlider(), GuiComboBox(), GuiDropdownBox(), GuiListView(), GuiMessageBox(), GuiInputBox() +static char **GuiTextSplit(const char *text, char delimiter, int *count) { // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, @@ -5461,24 +6094,19 @@ static char **GuiTextSplit(const char *text, char delimiter, int *count, int *te // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE // NOTE: Those definitions could be externally provided if required - // TODO: HACK: GuiTextSplit() - Review how textRows are returned to user - // textRow is an externally provided array of integers that stores row number for every splitted string - #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS) #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128 #endif #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE) - #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 + #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 // WARNING: Max expected size for all concat items #endif - static char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL }; // String pointers array (points to buffer data) + static char *itemPtrs[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { 0 }; // String pointers array (points to buffer data) static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; // Buffer data (text input copy with '\0' added) memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE); - result[0] = buffer; - int counter = 1; - - if (textRow != NULL) textRow[0] = 0; + itemPtrs[0] = buffer; + int itemCounter = 1; // Count how many substrings text contains and point to every one of them for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++) @@ -5487,24 +6115,16 @@ static char **GuiTextSplit(const char *text, char delimiter, int *count, int *te if (buffer[i] == '\0') break; else if ((buffer[i] == delimiter) || (buffer[i] == '\n')) { - result[counter] = buffer + i + 1; + itemPtrs[itemCounter] = buffer + i + 1; + buffer[i] = '\0'; // Set terminator for current item - if (textRow != NULL) - { - if (buffer[i] == '\n') textRow[counter] = textRow[counter - 1] + 1; - else textRow[counter] = textRow[counter - 1]; - } - - buffer[i] = '\0'; // Set an end of string at this point - - counter++; - if (counter >= RAYGUI_TEXTSPLIT_MAX_ITEMS) break; + itemCounter++; + if (itemCounter >= RAYGUI_TEXTSPLIT_MAX_ITEMS) break; } } - *count = counter; - - return result; + *count = itemCounter; + return itemPtrs; } // Convert color data from RGB to HSV @@ -5631,179 +6251,9 @@ static Vector3 ConvertHSVtoRGB(Vector3 hsv) return rgb; } -// Scroll bar control (used by GuiScrollPanel()) -static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) -{ - GuiState state = guiState; - - // Is the scrollbar horizontal or vertical? - bool isVertical = (bounds.width > bounds.height)? false : true; - - // The size (width or height depending on scrollbar type) of the spinner buttons - const int spinnerSize = GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)? - (isVertical? (int)bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) : - (int)bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0; - - // Arrow buttons [<] [>] [∧] [∨] - Rectangle arrowUpLeft = { 0 }; - Rectangle arrowDownRight = { 0 }; - - // Actual area of the scrollbar excluding the arrow buttons - Rectangle scrollbar = { 0 }; - - // Slider bar that moves --[///]----- - Rectangle slider = { 0 }; - - // Normalize value - if (value > maxValue) value = maxValue; - if (value < minValue) value = minValue; - - int valueRange = maxValue - minValue; - if (valueRange <= 0) valueRange = 1; - - int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); - if (sliderSize < 1) sliderSize = 1; // TODO: Consider a minimum slider size - - // Calculate rectangles for all of the components - arrowUpLeft = RAYGUI_CLITERAL(Rectangle){ - (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), - (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), - (float)spinnerSize, (float)spinnerSize }; - - if (isVertical) - { - arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + bounds.height - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; - scrollbar = RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), arrowUpLeft.y + arrowUpLeft.height, bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)), bounds.height - arrowUpLeft.height - arrowDownRight.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) }; - - // Make sure the slider won't get outside of the scrollbar - sliderSize = (sliderSize >= scrollbar.height)? ((int)scrollbar.height - 2) : sliderSize; - slider = RAYGUI_CLITERAL(Rectangle){ - bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), - scrollbar.y + (int)(((float)(value - minValue)/valueRange)*(scrollbar.height - sliderSize)), - bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)), - (float)sliderSize }; - } - else // horizontal - { - arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; - scrollbar = RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x + arrowUpLeft.width, bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), bounds.width - arrowUpLeft.width - arrowDownRight.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)) }; - - // Make sure the slider won't get outside of the scrollbar - sliderSize = (sliderSize >= scrollbar.width)? ((int)scrollbar.width - 2) : sliderSize; - slider = RAYGUI_CLITERAL(Rectangle){ - scrollbar.x + (int)(((float)(value - minValue)/valueRange)*(scrollbar.width - sliderSize)), - bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), - (float)sliderSize, - bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)) }; - } - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GUI_POINTER_POSITION; - - if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds - { - if (GUI_BUTTON_DOWN && - !CheckCollisionPointRec(mousePoint, arrowUpLeft) && - !CheckCollisionPointRec(mousePoint, arrowDownRight)) - { - if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) - { - state = STATE_PRESSED; - - if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); - else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); - } - } - else - { - guiControlExclusiveMode = false; - guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; - } - } - else if (CheckCollisionPointRec(mousePoint, bounds)) - { - state = STATE_FOCUSED; - - // Handle mouse wheel - float scrollDelta = GUI_SCROLL_DELTA; - if (scrollDelta != 0) value += (int)scrollDelta; - - // Handle mouse button down - if (GUI_BUTTON_PRESSED) - { - guiControlExclusiveMode = true; - guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts - - // Check arrows click - if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - else if (!CheckCollisionPointRec(mousePoint, slider)) - { - // If click on scrollbar position but not on slider, place slider directly on that position - if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); - else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); - } - - state = STATE_PRESSED; - } - - // Keyboard control on mouse hover scrollbar - /* - if (isVertical) - { - if (GUI_KEY_DOWN(KEY_DOWN)) value += 5; - else if (GUI_KEY_DOWN(KEY_UP)) value -= 5; - } - else - { - if (GUI_KEY_DOWN(KEY_RIGHT)) value += 5; - else if (GUI_KEY_DOWN(KEY_LEFT)) value -= 5; - } - */ - } - - // Normalize value - if (value > maxValue) value = maxValue; - if (value < minValue) value = minValue; - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED))); // Draw the background - - GuiDrawRectangle(scrollbar, 0, BLANK, GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL))); // Draw the scrollbar active area background - GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BORDER + state*3))); // Draw the slider bar - - // Draw arrows (using icon if available) - if (GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)) - { -#if defined(RAYGUI_NO_ICONS) - GuiDrawText(isVertical? "^" : "<", - RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); - GuiDrawText(isVertical? "v" : ">", - RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); -#else - GuiDrawText(isVertical? "#121#" : "#118#", - RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_UP_FILL / ICON_ARROW_LEFT_FILL - GuiDrawText(isVertical? "#120#" : "#119#", - RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_DOWN_FILL / ICON_ARROW_RIGHT_FILL -#endif - } - //-------------------------------------------------------------------- - - return value; -} - // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f -// WARNING: It multiplies current alpha by alpha scale factor +// WARNING: It multiplies current alpha by alpha scale factor, +// raylib Fade() multiplies alpha by 255.0f static Color GuiFade(Color color, float alpha) { if (alpha < 0.0f) alpha = 0.0f; @@ -5828,6 +6278,19 @@ static Color GetColor(int hexValue) return color; } +// Get color with alpha applied, alpha goes from 0.0f to 1.0f +static Color Fade(Color color, float alpha) +{ + Color result = color; + + if (alpha < 0.0f) alpha = 0.0f; + else if (alpha > 1.0f) alpha = 1.0f; + + result.a = (unsigned char)(255.0f*alpha); + + return result; +} + // Returns hexadecimal value for a Color static int ColorToInt(Color color) { @@ -5852,7 +6315,8 @@ static const char *TextFormat(const char *text, ...) #define RAYGUI_TEXTFORMAT_MAX_SIZE 256 #endif - static char buffer[RAYGUI_TEXTFORMAT_MAX_SIZE]; + static char buffer[RAYGUI_TEXTFORMAT_MAX_SIZE] = { 0 }; + memset(buffer, 0, RAYGUI_TEXTFORMAT_MAX_SIZE); va_list args; va_start(args, text); @@ -5862,61 +6326,6 @@ static const char *TextFormat(const char *text, ...) return buffer; } -// Draw rectangle with vertical gradient fill color -// NOTE: This function is only used by GuiColorPicker() -static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2) -{ - Rectangle bounds = { (float)posX, (float)posY, (float)width, (float)height }; - DrawRectangleGradientEx(bounds, color1, color2, color2, color1); -} - -// Split string into multiple strings -char **TextSplit(const char *text, char delimiter, int *count) -{ - // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) - // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, - // all used memory is static... it has some limitations: - // 1. Maximum number of possible split strings is set by RAYGUI_TEXTSPLIT_MAX_ITEMS - // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE - - #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS) - #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128 - #endif - #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE) - #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 - #endif - - static const char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL }; - static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; - memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE); - - result[0] = buffer; - int counter = 0; - - if (text != NULL) - { - counter = 1; - - // Count how many substrings text contains and point to every one of them - for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++) - { - buffer[i] = text[i]; - if (buffer[i] == '\0') break; - else if (buffer[i] == delimiter) - { - buffer[i] = '\0'; // Set an end of string at this point - result[counter] = buffer + i + 1; - counter++; - - if (counter == RAYGUI_TEXTSPLIT_MAX_ITEMS) break; - } - } - } - - *count = counter; - return result; -} - // Get integer value from text // NOTE: This function replaces atoi() [stdlib.h] static int TextToInteger(const char *text) diff --git a/examples/models/raygui.h b/examples/models/raygui.h index 58bd38bef..f7a116150 100644 --- a/examples/models/raygui.h +++ b/examples/models/raygui.h @@ -1,6 +1,6 @@ /******************************************************************************************* * -* raygui v5.0-dev - A simple and easy-to-use immediate-mode gui library +* raygui v5.0 - A simple and easy-to-use immediate-mode gui library * * DESCRIPTION: * raygui is a tools-dev-focused immediate-mode-gui library based on raylib but also @@ -37,7 +37,7 @@ * - Line * - Panel --> StatusBar * - ScrollPanel --> StatusBar -* - TabBar --> Button +* - TabBar --> Toggle, Button * * # Basic Controls * - Label @@ -134,6 +134,10 @@ * Includes custom ricons.h header defining a set of custom icons, * this file can be generated using rGuiIcons tool * +* #define RAYGUI_FONT_ICONS_BAKING +* On gui font loading from style file, append the icons to font atlas image, so, +* icons can be drawn along the text as a texture, instead of using shapes to draw them +* * #define RAYGUI_DEBUG_RECS_BOUNDS * Draw control bounds rectangles for debug * @@ -141,16 +145,26 @@ * Draw text bounds rectangles for debug * * VERSIONS HISTORY: -* 5.0 (xx-Mar-2026) ADDED: Support up to 32 controls (v500) +* 5.0 (20-Jul-2026) ADDED: NEW control: GuiTabBar() +* ADDED: Support up to 512 icons (v500) +* ADDED: Support icons baking into font atlas image * ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes -* ADDED: GuiValueBoxFloat() +* ADDED: GuiValueBoxFloat(), with floats support * ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP * ADDED: GuiListView() property: LIST_ITEMS_BORDER_WIDTH -* ADDED: GuiLoadIconsFromMemory() -* ADDED: Multiple new icons +* ADDED: GuiLoadIconsFromMemory(), used by GuiLoadIcons() * ADDED: Macros for inputs customization, raylib decoupling +* ADDED: Control result return values: 1-RESULT_PRESSED, 2-RESULT_CHANGED, >2-Control_custom * REMOVED: GuiSpinner() from controls list, using BUTTON + VALUEBOX properties * REMOVED: GuiSliderPro(), functionality was redundant +* REMOVED: TextSplit() raylib function requirement on RAYGUI_STANDALONE +* REDESIGNED: WARNING: GuiLoadStyleFromMemory() to support icons baking into font atlas +* REDESIGNED: GuiToggleGroup() to process rows/cols with no need for GuiTextSplit() +* REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion +* REDESIGNED: WARNING: TEXT_LINE_SPACING does not consider text height, only lines spacing +* REDESIGNED: WARNING: GuiMessageBox(), added parameter for btn return, unify result +* REDESIGNED: WARNING: GuiTextInputBox(), added parameter for btn return, unify result +* REVIEWED: GuiLoadIconsFromMemory(), fixed memory issues * REVIEWED: Controls using text labels to use LABEL properties * REVIEWED: Replaced sprintf() by snprintf() for more safety * REVIEWED: GuiTabBar(), close tab with mouse middle button @@ -165,8 +179,6 @@ * REVIEWED: GuiProgressBar(), improved borders computing * REVIEWED: GuiTextBox(), multiple improvements: autocursor and more * REVIEWED: Functions descriptions, removed wrong return value reference -* REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion -* REDESIGNED: WARNING: TEXT_LINE_SPACING does not consider text height, only lines spacing * * 4.0 (12-Sep-2023) ADDED: GuiToggleSlider() * ADDED: GuiColorPickerHSV() and GuiColorPanelHSV() @@ -273,7 +285,7 @@ * 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria * * DEPENDENCIES: -* raylib 5.6-dev - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing +* raylib 6.1-dev - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing * * STANDALONE MODE: * By default raygui depends on raylib mostly for the inputs and the drawing functionality but that dependency can be disabled @@ -340,10 +352,10 @@ #ifndef RAYGUI_H #define RAYGUI_H -#define RAYGUI_VERSION_MAJOR 4 -#define RAYGUI_VERSION_MINOR 5 +#define RAYGUI_VERSION_MAJOR 5 +#define RAYGUI_VERSION_MINOR 0 #define RAYGUI_VERSION_PATCH 0 -#define RAYGUI_VERSION "5.0-dev" +#define RAYGUI_VERSION "5.0" #if !defined(RAYGUI_STANDALONE) #include "raylib.h" @@ -357,9 +369,13 @@ #elif defined(USE_LIBTYPE_SHARED) #define RAYGUIAPI __declspec(dllimport) // Using the library as a Win32 shared library (.dll) #endif -#if !defined(_CRT_SECURE_NO_WARNINGS) - #define _CRT_SECURE_NO_WARNINGS // Disable unsafe warnings on scanf() functions in MSVC -#endif + #if !defined(_CRT_SECURE_NO_WARNINGS) + #define _CRT_SECURE_NO_WARNINGS // Disable unsafe warnings on scanf() functions in MSVC + #endif +#else + #if defined(BUILD_LIBTYPE_SHARED) + #define RAYGUIAPI __attribute__((visibility("default"))) // Building as a Unix shared library (.so/.dylib) + #endif #endif // Function specifiers definition @@ -379,8 +395,8 @@ #define RAYGUI_LOG(...) #endif +#if !defined(RAYGUI_STANDALONE) // Macros to define required UI inputs, including mapping to gamepad controls -// TODO: Define additionally required macros for missing inputs #if !defined(GUI_BUTTON_DOWN) #define GUI_BUTTON_DOWN (IsMouseButtonDown(MOUSE_LEFT_BUTTON) || IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) #endif @@ -391,13 +407,15 @@ #if !defined(GUI_BUTTON_PRESSED) #define GUI_BUTTON_PRESSED (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsGamepadButtonPressed(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) #endif -// TODO: WARNING: GuiTabBar() still requires IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON) +#if !defined(GUI_BUTTON_PRESSED_MID) + #define GUI_BUTTON_PRESSED_MID (IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON) || IsGamepadButtonPressed(0, GAMEPAD_BUTTON_RIGHT_FACE_UP)) +#endif #if !defined(GUI_BUTTON_RELEASED) #define GUI_BUTTON_RELEASED (IsMouseButtonReleased(MOUSE_LEFT_BUTTON) || IsGamepadButtonReleased(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) #endif #if !defined(GUI_SCROLL_DELTA) // Mapping to scroll delta changes - // TODO: Review inconsistencies between platforms + // TODO: Review mouse scroll inconsistencies between platforms #if defined(PLATFORM_WEB) // NOTE: Gamepad axis triggers not detected on web platform #define GUI_SCROLL_DELTA ((float)IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_TRIGGER_2) - (float)IsGamepadButtonDown(0, GAMEPAD_BUTTON_LEFT_TRIGGER_2)) @@ -417,6 +435,18 @@ #if !defined(GUI_INPUT_KEY) #define GUI_INPUT_KEY GetCharPressed() #endif +#else + #define GUI_BUTTON_DOWN 0 + #define GUI_BUTTON_DOWN_ALT 0 + #define GUI_BUTTON_PRESSED 0 + #define GUI_BUTTON_PRESSED_MID 0 + #define GUI_BUTTON_RELEASED 0 + #define GUI_SCROLL_DELTA 0 + #define GUI_POINTER_POSITION (Vector2){ 0 } + #define GUI_KEY_DOWN(key) 0 + #define GUI_KEY_PRESSED(key) 0 + #define GUI_INPUT_KEY 0 +#endif //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -451,6 +481,8 @@ unsigned char a; } Color; +#define BLANK (Color){ 0, 0, 0, 0 } // Blank (Transparent) + // Rectangle type typedef struct Rectangle { float x; @@ -459,7 +491,7 @@ float height; } Rectangle; - // TODO: Texture2D type is very coupled to raylib, required by Font type + // NOTE: Texture2D type is very coupled to raylib, required by Font type // It should be redesigned to be provided by user typedef struct Texture { unsigned int id; // OpenGL texture id @@ -490,7 +522,7 @@ Image image; // Character image data } GlyphInfo; - // TODO: Font type is very coupled to raylib, mostly required by GuiLoadStyle() + // NOTE: Font type is very coupled to raylib, mostly required by GuiLoadStyle() // It should be redesigned to be provided by user typedef struct Font { int baseSize; // Base size (default chars height) @@ -523,6 +555,15 @@ typedef struct GuiTextStyle { } GuiTextStyle; */ +// Gui control result +typedef enum { + RESULT_NONE = 0, + RESULT_PRESSED = 1, + RESULT_CHANGED = 2, + + RESULT_TAB_CLOSE = 4 // GuiTabBar(), tab close request +} GuiResult; + // Gui control state typedef enum { STATE_NORMAL = 0, @@ -555,88 +596,95 @@ typedef enum { } GuiTextWrapMode; // Gui controls +// NOTE: Up to 16 controls supported or 32 controls (v500) typedef enum { // Default -> populates to all controls when set - DEFAULT = 0, + DEFAULT = 0, // Basic controls - LABEL, // Used also for: LABELBUTTON - BUTTON, - TOGGLE, // Used also for: TOGGLEGROUP - SLIDER, // Used also for: SLIDERBAR, TOGGLESLIDER - PROGRESSBAR, - CHECKBOX, - COMBOBOX, - DROPDOWNBOX, - TEXTBOX, // Used also for: TEXTBOXMULTI - VALUEBOX, - CONTROL11, - LISTVIEW, - COLORPICKER, - SCROLLBAR, - STATUSBAR + LABEL = 1, // Used also for: LABELBUTTON + BUTTON = 2, + TOGGLE = 3, // Used also for: TOGGLEGROUP + SLIDER = 4, // Used also for: SLIDERBAR, TOGGLESLIDER + PROGRESSBAR = 5, + CHECKBOX = 6, + COMBOBOX = 7, + DROPDOWNBOX = 8, + TEXTBOX = 9, // Used also for: TEXTBOXMULTI + VALUEBOX = 10, + TABBAR = 11, + LISTVIEW = 12, + COLORPICKER = 13, + SCROLLBAR = 14, + STATUSBAR = 15 + // NOTE: More controls can be added if required } GuiControl; -// Gui base properties for every control -// NOTE: RAYGUI_MAX_PROPS_BASE properties (by default 16 properties) +// Controls BASE properties for every control (RAYGUI_MAX_PROPS_BASE = 16) +// NOTE: Properties required for all controls, DEFAULT control sets +// default values for them but they can be overriden per control typedef enum { - BORDER_COLOR_NORMAL = 0, // Control border color in STATE_NORMAL - BASE_COLOR_NORMAL, // Control base color in STATE_NORMAL - TEXT_COLOR_NORMAL, // Control text color in STATE_NORMAL - BORDER_COLOR_FOCUSED, // Control border color in STATE_FOCUSED - BASE_COLOR_FOCUSED, // Control base color in STATE_FOCUSED - TEXT_COLOR_FOCUSED, // Control text color in STATE_FOCUSED - BORDER_COLOR_PRESSED, // Control border color in STATE_PRESSED - BASE_COLOR_PRESSED, // Control base color in STATE_PRESSED - TEXT_COLOR_PRESSED, // Control text color in STATE_PRESSED - BORDER_COLOR_DISABLED, // Control border color in STATE_DISABLED - BASE_COLOR_DISABLED, // Control base color in STATE_DISABLED - TEXT_COLOR_DISABLED, // Control text color in STATE_DISABLED - BORDER_WIDTH = 12, // Control border size, 0 for no border - //TEXT_SIZE, // Control text size (glyphs max height) -> GLOBAL for all controls - //TEXT_SPACING, // Control text spacing between glyphs -> GLOBAL for all controls - //TEXT_LINE_SPACING, // Control text spacing between lines -> GLOBAL for all controls - TEXT_PADDING = 13, // Control text padding, not considering border - TEXT_ALIGNMENT = 14, // Control text horizontal alignment inside control text bound (after border and padding) - //TEXT_WRAP_MODE // Control text wrap-mode inside text bounds -> GLOBAL for all controls + BORDER_COLOR_NORMAL = 0, // Control border color in STATE_NORMAL + BASE_COLOR_NORMAL = 1, // Control base color in STATE_NORMAL + TEXT_COLOR_NORMAL = 2, // Control text color in STATE_NORMAL + BORDER_COLOR_FOCUSED = 3, // Control border color in STATE_FOCUSED + BASE_COLOR_FOCUSED = 4, // Control base color in STATE_FOCUSED + TEXT_COLOR_FOCUSED = 5, // Control text color in STATE_FOCUSED + BORDER_COLOR_PRESSED = 6, // Control border color in STATE_PRESSED + BASE_COLOR_PRESSED = 7, // Control base color in STATE_PRESSED + TEXT_COLOR_PRESSED = 8, // Control text color in STATE_PRESSED + BORDER_COLOR_DISABLED = 9, // Control border color in STATE_DISABLED + BASE_COLOR_DISABLED = 10, // Control base color in STATE_DISABLED + TEXT_COLOR_DISABLED = 11, // Control text color in STATE_DISABLED + BORDER_WIDTH = 12, // Control border size, 0 for no border + TEXT_PADDING = 13, // Control text padding, not considering border + TEXT_ALIGNMENT = 14, // Control text horizontal alignment inside control text bound (after border and padding): 0-Left, 1-Center, 2-Right + BASEPROP16 = 15 // Not used yet... } GuiControlProperty; -// TODO: Which text styling properties should be global or per-control? -// At this moment TEXT_PADDING and TEXT_ALIGNMENT is configured and saved per control while -// TEXT_SIZE, TEXT_SPACING, TEXT_LINE_SPACING, TEXT_ALIGNMENT_VERTICAL, TEXT_WRAP_MODE are global and -// should be configured by user as needed while defining the UI layout -// Gui extended properties depend on control -// NOTE: RAYGUI_MAX_PROPS_EXTENDED properties (by default, max 8 properties) +// WARNING: Some properties have been chosen to be global with DEFAULT - EXTENDED properties: +// - TEXT_SIZE, // Control text size (glyphs max height) +// - TEXT_SPACING, // Control text spacing between glyphs +// - TEXT_LINE_SPACING, // Control text spacing between lines +// - TEXT_WRAP_MODE // Control text wrap-mode inside text bounds +// +// While other properties can be setup per globally (DEFAULT) or per control: +// - TEXT_PADDING // Control text padding, not considering border +// - TEXT_ALIGNMENT // Control text horizontal alignment inside control text bound + + +// Controls EXTENDED properties (RAYGUI_MAX_PROPS_EXTENDED = 8) +// WARNING: Only 8 slots vailable for those properties per control, including DEFAULT //---------------------------------------------------------------------------------- -// DEFAULT extended properties -// NOTE: Those properties are common to all controls or global -// WARNING: Only 8 slots vailable for those properties by default +// DEFAULT control, extended properties +// NOTE: Those properties are global for all controls, they can not be setup per control typedef enum { - TEXT_SIZE = 16, // Text size (glyphs max height) - TEXT_SPACING, // Text spacing between glyphs - LINE_COLOR, // Line control color - BACKGROUND_COLOR, // Background color - TEXT_LINE_SPACING, // Text spacing between lines - TEXT_ALIGNMENT_VERTICAL, // Text vertical alignment inside text bounds (after border and padding) - TEXT_WRAP_MODE // Text wrap-mode inside text bounds - //TEXT_DECORATION // Text decoration: 0-None, 1-Underline, 2-Line-through, 3-Overline - //TEXT_DECORATION_THICK // Text decoration line thickness + TEXT_SIZE = 16, // Text size (glyphs max height) + TEXT_SPACING = 17, // Text spacing between glyphs + LINE_COLOR = 18, // Line control color + BACKGROUND_COLOR = 19, // Background color + TEXT_LINE_SPACING = 20, // Text spacing between lines + TEXT_ALIGNMENT_VERTICAL = 21, // Text vertical alignment inside text bounds (after border and padding): 0-Top, 1-Middle, 2-Bottom + TEXT_WRAP_MODE = 22, // Text wrap-mode inside text bounds + EXTPROP08 = 23 // Not used yet... } GuiDefaultProperty; -// Other possible text properties: -// TEXT_WEIGHT // Normal, Italic, Bold -> Requires specific font change -// TEXT_INDENT // Text indentation -> Now using TEXT_PADDING... +// Other possible text extended properties: +// TEXT_DECORATION // Text decoration: 0-None, 1-Underline, 2-Line-through, 3-Overline +// TEXT_DECORATION_THICK // Text decoration line thickness +// TEXT_FONT_WEIGHT // Text font weight: 0-Normal, 1-Bold, 2-Italic -> Requires specific font change // Label //typedef enum { } GuiLabelProperty; -// Button/Spinner +// Button //typedef enum { } GuiButtonProperty; // Toggle/ToggleGroup typedef enum { GROUP_PADDING = 16, // ToggleGroup separation between toggles + GROUP_WIDTH_FULL // ToggleGroup bounds width considers all items: 0-Width per item, 1-Full width } GuiToggleProperty; // Slider/SliderBar @@ -648,7 +696,7 @@ typedef enum { // ProgressBar typedef enum { PROGRESS_PADDING = 16, // ProgressBar internal padding - PROGRESS_SIDE, // ProgressBar increment side: 0-left->right, 1-right-left + PROGRESS_SIDE, // ProgressBar increment side: 0-Left->Right, 1-Right->Left } GuiProgressBarProperty; // ScrollBar @@ -677,12 +725,12 @@ typedef enum { ARROW_PADDING = 16, // DropdownBox arrow separation from border and items DROPDOWN_ITEMS_SPACING, // DropdownBox items separation DROPDOWN_ARROW_HIDDEN, // DropdownBox arrow hidden - DROPDOWN_ROLL_UP // DropdownBox roll up flag (default rolls down) + DROPDOWN_ROLL_UP // DropdownBox roll up flag: 0-Roll down, 1-Roll up } GuiDropdownBoxProperty; // TextBox/TextBoxMulti/ValueBox/Spinner typedef enum { - TEXT_READONLY = 16, // TextBox in read-only mode: 0-text editable, 1-text no-editable + TEXT_READONLY = 16, // TextBox in read-only mode: 0-Text editable, 1-Text read-only } GuiTextBoxProperty; // ValueBox/Spinner @@ -691,31 +739,35 @@ typedef enum { SPINNER_BUTTON_SPACING, // Spinner buttons separation } GuiValueBoxProperty; -// Control11 -//typedef enum { } GuiControl11Property; +// TabBar +typedef enum { + TAB_ITEMS_WIDTH = 16, // TabBar tab items width + TAB_CLOSE_BUTTON, // TabBar tab close button: 0-Not shown, 1-Shown + TAB_LINE_SIDE, // TabBar tabs side: 0-Bottom, 1-Top +} GuiTabBarProperty; // ListView +#define SCROLLBAR_LEFT_SIDE 0 +#define SCROLLBAR_RIGHT_SIDE 1 + typedef enum { LIST_ITEMS_HEIGHT = 16, // ListView items height LIST_ITEMS_SPACING, // ListView items separation SCROLLBAR_WIDTH, // ListView scrollbar size (usually width) - SCROLLBAR_SIDE, // ListView scrollbar side (0-SCROLLBAR_LEFT_SIDE, 1-SCROLLBAR_RIGHT_SIDE) + SCROLLBAR_SIDE, // ListView scrollbar side: 0-Left side, 1-Right Side LIST_ITEMS_BORDER_NORMAL, // ListView items border enabled in normal state LIST_ITEMS_BORDER_WIDTH // ListView items border width } GuiListViewProperty; // ColorPicker typedef enum { - COLOR_SELECTOR_SIZE = 16, + COLOR_SELECTOR_SIZE = 16, // ColorPicker selector square size HUEBAR_WIDTH, // ColorPicker right hue bar width HUEBAR_PADDING, // ColorPicker right hue bar separation from panel HUEBAR_SELECTOR_HEIGHT, // ColorPicker right hue bar selector height HUEBAR_SELECTOR_OVERFLOW // ColorPicker right hue bar selector overflow } GuiColorPickerProperty; -#define SCROLLBAR_LEFT_SIDE 0 -#define SCROLLBAR_RIGHT_SIDE 1 - //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- @@ -749,6 +801,7 @@ RAYGUIAPI int GuiGetStyle(int control, int property); // Get one style // Styles loading functions RAYGUIAPI void GuiLoadStyle(const char *fileName); // Load style file over global style variable (.rgs) +RAYGUIAPI void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only) RAYGUIAPI void GuiLoadStyleDefault(void); // Load style default over global style // Tooltips management functions @@ -762,6 +815,7 @@ RAYGUIAPI const char *GuiIconText(int iconId, const char *text); // Get text wit RAYGUIAPI void GuiSetIconScale(int scale); // Set default icon drawing size RAYGUIAPI unsigned int *GuiGetIcons(void); // Get raygui icons data pointer RAYGUIAPI char **GuiLoadIcons(const char *fileName, bool loadIconsName); // Load raygui icons file (.rgi) into internal icons data +RAYGUIAPI char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName); // Load raygui icons file (.rgi) from memory into internal icons data RAYGUIAPI void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color); // Draw icon using pixel size at specified position #endif @@ -775,7 +829,6 @@ RAYGUIAPI int GuiWindowBox(Rectangle bounds, const char *title); RAYGUIAPI int GuiGroupBox(Rectangle bounds, const char *text); // Group Box control with text name RAYGUIAPI int GuiLine(Rectangle bounds, const char *text); // Line separator control, could contain text RAYGUIAPI int GuiPanel(Rectangle bounds, const char *text); // Panel control, useful to group controls -RAYGUIAPI int GuiTabBar(Rectangle bounds, char **text, int count, int *active); // Tab Bar control, returns TAB to be closed or -1 RAYGUIAPI int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view); // Scroll Panel control // Basic controls set @@ -803,15 +856,17 @@ RAYGUIAPI int GuiGrid(Rectangle bounds, const char *text, float spacing, int sub // Advance controls set RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active); // List View control -RAYGUIAPI int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus); // List View with extended parameters -RAYGUIAPI int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons); // Message Box control, displays a message -RAYGUIAPI int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive); // Text Input Box control, ask for text, supports secret -RAYGUIAPI int GuiColorPicker(Rectangle bounds, const char *text, Color *color); // Color Picker control (multiple color controls) +RAYGUIAPI int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus); // List View control, using text entries list and returning focus entry +RAYGUIAPI int GuiTabBar(Rectangle bounds, const char *text, int *hscroll, int *active); // Tab Bar control +RAYGUIAPI int GuiTabBarEx(Rectangle bounds, char **text, int count, int *hscroll, int *active, int *focus); // Tab Bar control, using text entries list and returning focus entry +RAYGUIAPI int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *btnText, int *btnActive); // Message Box control, displays a message +RAYGUIAPI int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, char *text, int textSize, const char *btnText, int *btnActive, bool *secretViewActive); // Text Input Box control, ask for text, supports secret +RAYGUIAPI int GuiColorPicker(Rectangle bounds, const char *text, Color *color); // Color Picker control, includes Color bar controls RAYGUIAPI int GuiColorPanel(Rectangle bounds, const char *text, Color *color); // Color Panel control RAYGUIAPI int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha); // Color Bar Alpha control RAYGUIAPI int GuiColorBarHue(Rectangle bounds, const char *text, float *value); // Color Bar Hue control -RAYGUIAPI int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Picker control that avoids conversion to RGB on each call (multiple color controls) -RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control that updates Hue-Saturation-Value color value, used by GuiColorPickerHSV() +RAYGUIAPI int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Picker control, using Hue-Saturation-Value color data, includes Color bar controls +RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control, using Hue-Saturation-Value color data //---------------------------------------------------------------------------------------------------------- #if !defined(RAYGUI_NO_ICONS) @@ -1071,16 +1126,17 @@ typedef enum { ICON_CONE = 247, ICON_ELLIPSOID = 248, ICON_CAPSULE = 249, - ICON_250 = 250, - ICON_251 = 251, - ICON_252 = 252, - ICON_253 = 253, - ICON_254 = 254, - ICON_255 = 255 + ICON_FILETYPE_FONT = 250, + ICON_FILETYPE_3D = 251, + ICON_FILETYPE_CODE_XML = 252, + ICON_FILETYPE_CODE_C = 253, + ICON_FILETYPE_CODE_PYTHON = 254, + ICON_FILETYPE_CODE_JS = 255, + ICON_FILETYPE_ICON = 256, } GuiIconName; #endif -#endif +#endif // RAYGUI_NO_ICONS #if defined(__cplusplus) } // Prevents name mangling of functions @@ -1096,11 +1152,11 @@ typedef enum { #if defined(RAYGUI_IMPLEMENTATION) -#include // required for: isspace() [GuiTextBox()] #include // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()] #include // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy() #include // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()] #include // Required for: roundf() [GuiColorPicker()] +#include // Required for: isspace() [GuiTextBox()] // Allow custom memory allocators #if defined(RAYGUI_MALLOC) || defined(RAYGUI_CALLOC) || defined(RAYGUI_FREE) @@ -1129,9 +1185,11 @@ typedef enum { #if !defined(RAYGUI_NO_ICONS) && !defined(RAYGUI_CUSTOM_ICONS) // Embedded icons, no external file provided -#define RAYGUI_ICON_SIZE 16 // Size of icons in pixels (squared) -#define RAYGUI_ICON_MAX_ICONS 256 // Maximum number of icons -#define RAYGUI_ICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id +#define RAYGUI_ICON_SIZE 16 // Size of icons in pixels (squared) +#define RAYGUI_ICON_MAX_ICONS 512 // Maximum number of icons +#define RAYGUI_ICON_MAX_FONT_BACKED 257 // Maximum number of icons to back in font atlas +#define RAYGUI_ICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id +#define RAYGUI_ICON_FONT_ATLAS_PADDING 1 // Padding between backed icons in font atlas // Icons data is defined by bit array (every bit represents one pixel) // Those arrays are stored as unsigned int data arrays, so, @@ -1149,7 +1207,7 @@ typedef enum { // NOTE 2: A different icon set could be loaded over this array using GuiLoadIcons(), // but loaded icons set must be same RAYGUI_ICON_SIZE and no more than RAYGUI_ICON_MAX_ICONS // -// guiIcons size is by default: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 KB +// guiIcons size is by default: 512*(16*16/32) = 16384 bytes = 16 KB //---------------------------------------------------------------------------------- static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_NONE @@ -1402,18 +1460,20 @@ static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = 0x00800000, 0x01400140, 0x02200220, 0x04100410, 0x08080808, 0x1c1c13e4, 0x08081004, 0x000007f0, // ICON_CONE 0x00000000, 0x07e00000, 0x20841918, 0x40824082, 0x40824082, 0x19182084, 0x000007e0, 0x00000000, // ICON_ELLIPSOID 0x00000000, 0x00000000, 0x20041ff8, 0x40024002, 0x40024002, 0x1ff82004, 0x00000000, 0x00000000, // ICON_CAPSULE - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_250 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_251 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_252 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_253 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_254 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_255 + 0x3ff00000, 0x201c2010, 0x21042004, 0x22842384, 0x264426c4, 0x2c242fe4, 0x20043e74, 0x00003ffc, // ICON_FILETYPE_FONT + 0x3ff00000, 0x201c2010, 0x20042004, 0x27742004, 0x29742944, 0x27742944, 0x20042004, 0x00003ffc, // ICON_FILETYPE_3D + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x24242244, 0x24242814, 0x20042244, 0x00003ffc, // ICON_FILETYPE_XML + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x21042f04, 0x21042104, 0x20042f04, 0x00003ffc, // ICON_FILETYPE_C + 0x3ff00000, 0x201c2010, 0x23842004, 0x2bf42a04, 0x2fd42814, 0x21c42054, 0x20042004, 0x00003ffc, // ICON_FILETYPE_PYTHON + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x22842ee4, 0x28a42e84, 0x20042e64, 0x00003ffc, // ICON_FILETYPE_JS + 0x3ff00000, 0x241c2010, 0x2a8c3104, 0x28242454, 0x2ed42004, 0x2a542a54, 0x20042ed4, 0x00003ffc, // ICON_FILETYPE_ICON + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_257 }; // NOTE: A pointer to current icons array should be defined static unsigned int *guiIconsPtr = guiIcons; -#endif // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS +#endif // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS #ifndef RAYGUI_ICON_SIZE #define RAYGUI_ICON_SIZE 0 @@ -1437,10 +1497,12 @@ typedef enum { BORDER = 0, BASE, TEXT, OTHER } GuiPropertyElement; static GuiState guiState = STATE_NORMAL; // Gui global state, if !STATE_NORMAL, forces defined state static Font guiFont = { 0 }; // Gui current font (WARNING: highly coupled to raylib) +static char guiFontName[32] = { 0 }; // Gui font filename, can be loaded from .rgs (Version: >=600) static bool guiLocked = false; // Gui lock state (no inputs processed) static float guiAlpha = 1.0f; // Gui controls transparency static unsigned int guiIconScale = 1; // Gui icon default scale (if icons enabled) +static unsigned int guiIconFontOffsetY = 0; // Gui icon font atlas offset (if icons backed) static bool guiTooltip = false; // Tooltip enabled/disabled static const char *guiTooltipPtr = NULL; // Tooltip string pointer (string provided by user) @@ -1521,22 +1583,22 @@ static int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle( static void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list static unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle() + +static Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font //------------------------------------------------------------------------------- // raylib functions already implemented in raygui //------------------------------------------------------------------------------- static Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value +static Color Fade(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f static int ColorToInt(Color color); // Returns hexadecimal value for a Color static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed' -static char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings static int TextToInteger(const char *text); // Get integer value from text static float TextToFloat(const char *text); // Get float value from text static int GetCodepointNext(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded text static const char *CodepointToUTF8(int codepoint, int *byteSize); // Encode codepoint into UTF-8 text (char array size returned as parameter) - -static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2); // Draw rectangle vertical gradient //------------------------------------------------------------------------------- #endif // RAYGUI_STANDALONE @@ -1544,22 +1606,22 @@ static void DrawRectangleGradientV(int posX, int posY, int width, int height, Co //---------------------------------------------------------------------------------- // Module Internal Functions Declaration //---------------------------------------------------------------------------------- -static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only) - +static int GetLineWidth(const char *text); // Get text line width (stops at '\n' or '\0') static Rectangle GetTextBounds(int control, Rectangle bounds); // Get text bounds considering control bounds static const char *GetTextIcon(const char *text, int *iconId); // Get text icon if provided and move text cursor -static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint); // Gui draw text using default font -static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // Gui draw rectangle using default raygui style +static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint); // Gui draw text using default font +static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // Gui draw rectangle using default raygui style -static char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow); // Split controls text into multiple strings +static char **GuiTextSplit(const char *text, char delimiter, int *count); // Split controls text into multiple strings static Vector3 ConvertHSVtoRGB(Vector3 hsv); // Convert color data from HSV to RGB static Vector3 ConvertRGBtoHSV(Vector3 rgb); // Convert color data from RGB to HSV -static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel() static void GuiTooltip(Rectangle controlRec); // Draw tooltip using control rec position +static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel() +static int GuiFontIconBaking(Image *imFont, Font font, Rectangle *whiteRec); // Update font image atlas to append raygui icons -static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor +static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor //---------------------------------------------------------------------------------- // Gui Setup Functions Definition @@ -1602,7 +1664,7 @@ void GuiSetFont(Font font) { if (font.texture.id > 0) { - // NOTE: If a font is tried to be set but default style has not been lazily loaded first, + // NOTE: If a font is tried to be set but default style has not been lazily loaded first, // it will be overwritten, so default style loading needs to be forced first if (!guiStyleLoaded) GuiLoadStyleDefault(); @@ -1653,7 +1715,7 @@ int GuiWindowBox(Rectangle bounds, const char *title) #define RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT 18 #endif - int result = 0; + int result = RESULT_NONE; //GuiState state = guiState; int statusBarHeight = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT; @@ -1675,11 +1737,15 @@ int GuiWindowBox(Rectangle bounds, const char *title) // Draw control //-------------------------------------------------------------------- GuiPanel(windowPanel, NULL); // Draw window base + + int tempTextAlignment = GuiGetStyle(STATUSBAR, TEXT_ALIGNMENT); + GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); GuiStatusBar(statusBar, title); // Draw window header as status bar + GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, tempTextAlignment); // Draw window close button int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); - int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); GuiSetStyle(BUTTON, BORDER_WIDTH, 1); GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); #if defined(RAYGUI_NO_ICONS) @@ -1691,7 +1757,7 @@ int GuiWindowBox(Rectangle bounds, const char *title) GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); //-------------------------------------------------------------------- - return result; // Window close button clicked: result = 1 + return result; } // Group Box control with text name @@ -1701,7 +1767,7 @@ int GuiGroupBox(Rectangle bounds, const char *text) #define RAYGUI_GROUPBOX_LINE_THICK 1 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Draw control @@ -1726,7 +1792,7 @@ int GuiLine(Rectangle bounds, const char *text) #define RAYGUI_LINE_TEXT_PADDING 4 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; Color color = GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)); @@ -1759,7 +1825,7 @@ int GuiPanel(Rectangle bounds, const char *text) #define RAYGUI_PANEL_BORDER_WIDTH 1 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Text will be drawn as a header bar (if provided) @@ -1775,7 +1841,7 @@ int GuiPanel(Rectangle bounds, const char *text) // Draw control //-------------------------------------------------------------------- - if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar + if (text != NULL) result = GuiStatusBar(statusBar, text); // Draw panel header as status bar GuiDrawRectangle(bounds, RAYGUI_PANEL_BORDER_WIDTH, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)), GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BASE_COLOR_DISABLED : (int)BACKGROUND_COLOR))); @@ -1784,81 +1850,6 @@ int GuiPanel(Rectangle bounds, const char *text) return result; } -// Tab Bar control -// NOTE: Using GuiToggle() for the TABS -int GuiTabBar(Rectangle bounds, char **text, int count, int *active) -{ - #define RAYGUI_TABBAR_ITEM_WIDTH 148 - - int result = -1; - //GuiState state = guiState; - - Rectangle tabBounds = { bounds.x, bounds.y, RAYGUI_TABBAR_ITEM_WIDTH, bounds.height }; - - if (*active < 0) *active = 0; - else if (*active > count - 1) *active = count - 1; - - int offsetX = 0; // Required in case tabs go out of screen - offsetX = (*active + 2)*RAYGUI_TABBAR_ITEM_WIDTH - GetScreenWidth(); - if (offsetX < 0) offsetX = 0; - - bool toggle = false; // Required for individual toggles - - // Draw control - //-------------------------------------------------------------------- - for (int i = 0; i < count; i++) - { - tabBounds.x = bounds.x + (RAYGUI_TABBAR_ITEM_WIDTH + 4)*i - offsetX; - - if (tabBounds.x < GetScreenWidth()) - { - // Draw tabs as toggle controls - int textAlignment = GuiGetStyle(TOGGLE, TEXT_ALIGNMENT); - int textPadding = GuiGetStyle(TOGGLE, TEXT_PADDING); - GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); - GuiSetStyle(TOGGLE, TEXT_PADDING, 8); - - if (i == (*active)) - { - toggle = true; - GuiToggle(tabBounds, text[i], &toggle); - } - else - { - toggle = false; - GuiToggle(tabBounds, text[i], &toggle); - if (toggle) *active = i; - } - - // Close tab with middle mouse button pressed - if (CheckCollisionPointRec(GUI_POINTER_POSITION, tabBounds) && IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON)) result = i; - - GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding); - GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment); - - // Draw tab close button - // NOTE: Only draw close button for current tab: if (CheckCollisionPointRec(mousePosition, tabBounds)) - int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); - int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); - GuiSetStyle(BUTTON, BORDER_WIDTH, 1); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); -#if defined(RAYGUI_NO_ICONS) - if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, "x")) result = i; -#else - if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, GuiIconText(ICON_CROSS_SMALL, NULL))) result = i; -#endif - GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); - } - } - - // Draw tab-bar bottom line - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, 1 }, 0, BLANK, GetColor(GuiGetStyle(TOGGLE, BORDER_COLOR_NORMAL))); - //-------------------------------------------------------------------- - - return result; // Return as result the current TAB closing requested -} - // Scroll Panel control int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view) { @@ -1866,7 +1857,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector #define RAYGUI_MIN_SCROLLBAR_HEIGHT 40 #define RAYGUI_MIN_MOUSE_WHEEL_SPEED 20 - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; Rectangle temp = { 0 }; @@ -1923,7 +1914,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector float horizontalMin = hasHorizontalScrollBar? ((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH); float horizontalMax = hasHorizontalScrollBar? content.width - bounds.width + (float)verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH) - (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)verticalScrollBarWidth : 0) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); - float verticalMin = hasVerticalScrollBar? 0.0f : -1.0f; + float verticalMin = -(float)GuiGetStyle(DEFAULT, BORDER_WIDTH); float verticalMax = hasVerticalScrollBar? content.height - bounds.height + (float)horizontalScrollBarWidth + (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); // Update control @@ -1973,7 +1964,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector // Draw control //-------------------------------------------------------------------- - if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar + if (text != NULL) result = GuiStatusBar(statusBar, text); // Draw panel header as status bar GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background @@ -2020,7 +2011,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector // Label control int GuiLabel(Rectangle bounds, const char *text) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Update control @@ -2039,7 +2030,7 @@ int GuiLabel(Rectangle bounds, const char *text) // Button control, returns true when clicked int GuiButton(Rectangle bounds, const char *text) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Update control @@ -2054,7 +2045,7 @@ int GuiButton(Rectangle bounds, const char *text) if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; - if (GUI_BUTTON_RELEASED) result = 1; + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; } } //-------------------------------------------------------------------- @@ -2067,14 +2058,14 @@ int GuiButton(Rectangle bounds, const char *text) if (state == STATE_FOCUSED) GuiTooltip(bounds); //------------------------------------------------------------------ - return result; // Button pressed: result = 1 + return result; } // Label button control int GuiLabelButton(Rectangle bounds, const char *text) { + int result = RESULT_NONE; GuiState state = guiState; - bool pressed = false; // NOTE: Force bounds.width to be all text float textWidth = (float)GuiGetTextWidth(text); @@ -2092,7 +2083,7 @@ int GuiLabelButton(Rectangle bounds, const char *text) if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; - if (GUI_BUTTON_RELEASED) pressed = true; + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; } } //-------------------------------------------------------------------- @@ -2102,13 +2093,13 @@ int GuiLabelButton(Rectangle bounds, const char *text) GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); //-------------------------------------------------------------------- - return pressed; + return result; } // Toggle Button control int GuiToggle(Rectangle bounds, const char *text, bool *active) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; bool temp = false; @@ -2128,6 +2119,8 @@ int GuiToggle(Rectangle bounds, const char *text, bool *active) { state = STATE_NORMAL; *active = !(*active); + + result = RESULT_CHANGED; } else state = STATE_FOCUSED; } @@ -2156,68 +2149,110 @@ int GuiToggle(Rectangle bounds, const char *text, bool *active) // Toggle Group control int GuiToggleGroup(Rectangle bounds, const char *text, int *active) { - #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEMS) - #define RAYGUI_TOGGLEGROUP_MAX_ITEMS 32 + int result = RESULT_NONE; + + #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE) + #define RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE 256 #endif - int result = 0; - float initBoundsX = bounds.x; + // One toggle group item text + static char itemText[RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE] = { 0 }; + memset(itemText, 0, RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE); int temp = 0; + int prevActive = (active == NULL)? 0 : *active; if (active == NULL) active = &temp; bool toggle = false; // Required for individual toggles - // Get substrings items from text (items pointers) - int rows[RAYGUI_TOGGLEGROUP_MAX_ITEMS] = { 0 }; - int itemCount = 0; - char **items = GuiTextSplit(text, ';', &itemCount, rows); + const char *textPtr = text; + bool itemReady = false; + float initBoundsX = bounds.x; + float initBoundsY = bounds.y; - int prevRow = rows[0]; - - for (int i = 0; i < itemCount; i++) + if (GuiGetStyle(TOGGLE, GROUP_WIDTH_FULL)) { - if (prevRow != rows[i]) - { - bounds.x = initBoundsX; - bounds.y += (bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING)); - prevRow = rows[i]; - } + // Calculate item width considring all horizontal items + // NOTE: bounds.height still considers individual items height + int itemCount = 1; + for (int c = 0; textPtr[c] != '\0'; c++) { if (textPtr[c] == ';') itemCount++; } + bounds.width /= itemCount; + } - if (i == (*active)) + // Text parsing needed to consider potential row and col entries (vertical/horizontal layout) + // when '\n' found move vertically next toggle, when ';' found move horizontally + for (int c = 0, k = 0, itemIndex = 0, row = 0, col = 0, exit = 0; exit == 0; c++) + { + // Process text to get items one by one + // NOTE: Setting columns and rows index properly + if (textPtr[c] == '\n') { - toggle = true; - GuiToggle(bounds, items[i], &toggle); + row++; + col = 0; + itemReady = true; + } + else if (textPtr[c] == ';') + { + col++; + itemReady = true; + } + else if (textPtr[c] == '\0') + { + itemReady = true; + exit = 1; } else { - toggle = false; - GuiToggle(bounds, items[i], &toggle); - if (toggle) *active = i; + itemText[k] = textPtr[c]; + k++; } - bounds.x += (bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING)); + if (itemReady) + { + // When a next item is ready, draw its toggle + if (itemIndex == (*active)) + { + toggle = true; + GuiToggle(bounds, itemText, &toggle); + } + else + { + toggle = false; + GuiToggle(bounds, itemText, &toggle); + if (toggle) *active = itemIndex; + } + + // Calculate next item position + bounds.x = initBoundsX + col*(bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING)); + bounds.y = initBoundsY + row*(bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING)); + + itemIndex++; + itemReady = false; + memset(itemText, 0, k + 1); + k = 0; + } } + if (prevActive != *active) result = RESULT_CHANGED; + return result; } // Toggle Slider control extended int GuiToggleSlider(Rectangle bounds, const char *text, int *active) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; int temp = 0; + int prevActive = (active == NULL)? 0 : *active; if (active == NULL) active = &temp; - //bool toggle = false; // Required for individual toggles - // Get substrings items from text (items pointers) int itemCount = 0; char **items = NULL; - if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL); + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount); Rectangle slider = { 0, // Calculated later depending on the active toggle @@ -2248,6 +2283,8 @@ int GuiToggleSlider(Rectangle bounds, const char *text, int *active) if (*active >= itemCount) *active = 0; slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH) + (*active + 1)*GuiGetStyle(SLIDER, SLIDER_PADDING) + (*active)*slider.width; + + if (prevActive != *active) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -2279,7 +2316,7 @@ int GuiToggleSlider(Rectangle bounds, const char *text, int *active) // Check Box control, returns 1 when state changed int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; bool temp = false; @@ -2318,7 +2355,8 @@ int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) if (GUI_BUTTON_RELEASED) { *checked = !(*checked); - result = 1; + + result = RESULT_CHANGED; } } } @@ -2346,10 +2384,11 @@ int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) // Combo Box control int GuiComboBox(Rectangle bounds, const char *text, int *active) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; int temp = 0; + int prevActive = (active == NULL)? 0 : *active; if (active == NULL) active = &temp; bounds.width -= (GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH) + GuiGetStyle(COMBOBOX, COMBO_BUTTON_SPACING)); @@ -2359,7 +2398,7 @@ int GuiComboBox(Rectangle bounds, const char *text, int *active) // Get substrings items from text (items pointers, lengths and count) int itemCount = 0; - char **items = GuiTextSplit(text, ';', &itemCount, NULL); + char **items = GuiTextSplit(text, ';', &itemCount); if (*active < 0) *active = 0; else if (*active > (itemCount - 1)) *active = itemCount - 1; @@ -2373,16 +2412,18 @@ int GuiComboBox(Rectangle bounds, const char *text, int *active) if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + if (GUI_BUTTON_PRESSED) { *active += 1; if (*active >= itemCount) *active = 0; // Cyclic combobox } - - if (GUI_BUTTON_DOWN) state = STATE_PRESSED; - else state = STATE_FOCUSED; } } + + if (prevActive != *active) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -2411,10 +2452,11 @@ int GuiComboBox(Rectangle bounds, const char *text, int *active) // NOTE: Returns mouse click int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; int temp = 0; + int prevActive = (active == NULL)? 0 : *active; if (active == NULL) active = &temp; int itemSelected = *active; @@ -2425,7 +2467,7 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod // Get substrings items from text (items pointers, lengths and count) int itemCount = 0; - char **items = GuiTextSplit(text, ';', &itemCount, NULL); + char **items = GuiTextSplit(text, ';', &itemCount); Rectangle boundsOpen = bounds; boundsOpen.height = (itemCount + 1)*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); @@ -2525,7 +2567,8 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 }, TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); #else - GuiDrawText(direction? "#121#" : "#120#", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 }, + GuiDrawText(direction? GuiIconText(ICON_ARROW_UP_FILL, NULL) : GuiIconText(ICON_ARROW_DOWN_FILL, NULL), + RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 }, TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); // ICON_ARROW_DOWN_FILL #endif } @@ -2533,8 +2576,9 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod *active = itemSelected; - // TODO: Use result to return more internal states: mouse-press out-of-bounds, mouse-press over selected-item... - return result; // Mouse click: result = 1 + if (prevActive != *active) result = RESULT_CHANGED; + + return result; } // Text Box control @@ -2548,10 +2592,10 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) #define RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY 1 // Frames delay for autocursor movement #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; - bool multiline = false; // TODO: Consider multiline text input + bool multiline = false; int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); Rectangle textBounds = GetTextBounds(TEXTBOX, bounds); @@ -2598,7 +2642,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) { // GLOBAL: Auto-cursor movement logic // NOTE: Keystrokes are handled repeatedly when button is held down for some time - if (GUI_KEY_DOWN(KEY_LEFT) || GUI_KEY_DOWN(KEY_RIGHT) || GUI_KEY_DOWN(KEY_UP) || GUI_KEY_DOWN(KEY_DOWN) || GUI_KEY_DOWN(KEY_BACKSPACE) || GUI_KEY_DOWN(KEY_DELETE)) autoCursorCounter++; + if (GUI_KEY_DOWN(KEY_LEFT) || GUI_KEY_DOWN(KEY_RIGHT) || + GUI_KEY_DOWN(KEY_UP) || GUI_KEY_DOWN(KEY_DOWN) || + GUI_KEY_DOWN(KEY_BACKSPACE) || GUI_KEY_DOWN(KEY_DELETE)) autoCursorCounter++; else autoCursorCounter = 0; bool autoCursorShouldTrigger = (autoCursorCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN) && ((autoCursorCounter % RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0); @@ -2656,6 +2702,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) textBoxCursorIndex += pasteLength; textLength += pasteLength; text[textLength] = '\0'; + + //result = RESULT_CHANGED; } } } @@ -2674,6 +2722,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) // Make sure text last character is EOL text[textLength] = '\0'; + + //result = RESULT_CHANGED; } // Move cursor to start @@ -2696,8 +2746,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) bool puctuation = ispunct(nextCodepoint & 0xff); while (offset < textLength) { - if ((puctuation && !ispunct(nextCodepoint & 0xff)) || (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff)))) - break; + if ((puctuation && !ispunct(nextCodepoint & 0xff)) || + (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff)))) break; + offset += nextCodepointSize; accCodepointSize += nextCodepointSize; nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); @@ -2717,9 +2768,11 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) for (int i = offset; i <= textLength; i++) text[i - accCodepointSize] = text[i]; textLength -= accCodepointSize; - } - else if ((textLength > textBoxCursorIndex) && (GUI_KEY_PRESSED(KEY_DELETE) || (GUI_KEY_DOWN(KEY_DELETE) && autoCursorShouldTrigger))) + //result = RESULT_CHANGED; + } + else if ((textLength > textBoxCursorIndex) && (GUI_KEY_PRESSED(KEY_DELETE) || + (GUI_KEY_DOWN(KEY_DELETE) && autoCursorShouldTrigger))) { // Delete single codepoint from text, after current cursor position @@ -2730,10 +2783,13 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) for (int i = textBoxCursorIndex + nextCodepointSize; i <= textLength; i++) text[i - nextCodepointSize] = text[i]; textLength -= nextCodepointSize; + + //result = RESULT_CHANGED; } // Delete related codepoints from text, before current cursor position - if ((textBoxCursorIndex > 0) && GUI_KEY_PRESSED(KEY_BACKSPACE) && (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) + if ((textBoxCursorIndex > 0) && GUI_KEY_PRESSED(KEY_BACKSPACE) && + (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) { int offset = textBoxCursorIndex; int accCodepointSize = 0; @@ -2756,7 +2812,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) while (offset > 0) { prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize); - if ((puctuation && !ispunct(prevCodepoint & 0xff)) || (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break; + if ((puctuation && !ispunct(prevCodepoint & 0xff)) || + (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break; offset -= prevCodepointSize; accCodepointSize += prevCodepointSize; @@ -2767,8 +2824,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) textLength -= accCodepointSize; textBoxCursorIndex -= accCodepointSize; - } + //result = RESULT_CHANGED; + } else if ((textBoxCursorIndex > 0) && (GUI_KEY_PRESSED(KEY_BACKSPACE) || (GUI_KEY_DOWN(KEY_BACKSPACE) && autoCursorShouldTrigger))) { // Delete single codepoint from text, before current cursor position @@ -2782,6 +2840,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) textLength -= prevCodepointSize; textBoxCursorIndex -= prevCodepointSize; + + //result = RESULT_CHANGED; } // Move cursor position with keys @@ -2864,7 +2924,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) } // Move cursor position with mouse - if (CheckCollisionPointRec(mousePosition, textBounds)) // Mouse hover text + if (CheckCollisionPointRec(mousePosition, textBounds)) { float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/(float)guiFont.baseSize; int codepointIndex = 0; @@ -2917,7 +2977,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) { textBoxCursorIndex = 0; // GLOBAL: Reset the shared cursor index autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes - result = 1; + + //*editMode = false; + result = RESULT_PRESSED; } } else @@ -2930,7 +2992,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) { textBoxCursorIndex = textLength; // GLOBAL: Place cursor index to the end of current text autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes - result = 1; + + //*editMode = true; + result = RESULT_PRESSED; } } } @@ -2965,7 +3029,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) else if (state == STATE_FOCUSED) GuiTooltip(bounds); //-------------------------------------------------------------------- - return result; // Mouse button pressed: result = 1 + return result; } /* @@ -3063,21 +3127,24 @@ int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); //-------------------------------------------------------------------- + //if (tempValue != *value) result = RESULT_CHANGED; // WARNING: Stops editing + *value = tempValue; + return result; } // Value Box control, updates input text with numbers -// NOTE: Requires static variables: frameCounter int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) { #if !defined(RAYGUI_VALUEBOX_MAX_CHARS) #define RAYGUI_VALUEBOX_MAX_CHARS 32 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; + //int prevValue = *value; char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = { 0 }; snprintf(textValue, RAYGUI_VALUEBOX_MAX_CHARS + 1, "%i", *value); @@ -3164,7 +3231,7 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in if (*value > maxValue) *value = maxValue; else if (*value < minValue) *value = minValue; - result = 1; + result = RESULT_PRESSED; } } else @@ -3175,10 +3242,13 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in if (CheckCollisionPointRec(mousePoint, bounds)) { state = STATE_FOCUSED; - if (GUI_BUTTON_PRESSED) result = 1; + + if (GUI_BUTTON_PRESSED) result = RESULT_PRESSED; } } } + + //if (prevValue != *value) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3209,18 +3279,16 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in } // Floating point Value Box control, updates input val_str with numbers -// NOTE: Requires static variables: frameCounter int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode) { #if !defined(RAYGUI_VALUEBOX_MAX_CHARS) #define RAYGUI_VALUEBOX_MAX_CHARS 32 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; - //char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0"; - //snprintf(textValue, sizeof(textValue), "%2.2f", *value); + //float prevValue = *value; Rectangle textBounds = { 0 }; if (text != NULL) @@ -3305,17 +3373,21 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float if (valueHasChanged) *value = TextToFloat(textValue); - if ((GUI_KEY_PRESSED(KEY_ENTER) || GUI_KEY_PRESSED(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && GUI_BUTTON_PRESSED)) result = 1; + if ((GUI_KEY_PRESSED(KEY_ENTER) || GUI_KEY_PRESSED(KEY_KP_ENTER)) || + (!CheckCollisionPointRec(mousePoint, bounds) && GUI_BUTTON_PRESSED)) result = RESULT_PRESSED; } else { if (CheckCollisionPointRec(mousePoint, bounds)) { state = STATE_FOCUSED; - if (GUI_BUTTON_PRESSED) result = 1; + + if (GUI_BUTTON_PRESSED) result = RESULT_PRESSED; } } } + + //if (prevValue != *value) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3338,8 +3410,7 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float } // Draw text label if provided - GuiDrawText(text, textBounds, - (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, + GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); //-------------------------------------------------------------------- @@ -3350,12 +3421,13 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float // NOTE: Other GuiSlider*() controls use this one int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; float temp = (maxValue - minValue)/2.0f; if (value == NULL) value = &temp; - float oldValue = *value; + + float prevValue = *value; int sliderWidth = GuiGetStyle(SLIDER, SLIDER_WIDTH); @@ -3406,10 +3478,6 @@ int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, flo else if (*value < minValue) *value = minValue; } - // Control value change check - if (oldValue == *value) result = 0; - else result = 1; - // Slider bar limits check float sliderValue = (((*value - minValue)/(maxValue - minValue))*(bounds.width - sliderWidth - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))); if (sliderWidth > 0) // Slider @@ -3425,6 +3493,8 @@ int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, flo slider.width = sliderValue; if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH); } + + if (prevValue != *value) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3467,7 +3537,7 @@ int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, flo // Slider Bar control extended, returns selected value int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) { - int result = 0; + int result = RESULT_NONE; int preSliderWidth = GuiGetStyle(SLIDER, SLIDER_WIDTH); GuiSetStyle(SLIDER, SLIDER_WIDTH, 0); result = GuiSlider(bounds, textLeft, textRight, value, minValue, maxValue); @@ -3479,11 +3549,12 @@ int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, // Progress Bar control extended, shows current progress value int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; float temp = (maxValue - minValue)/2.0f; if (value == NULL) value = &temp; + float prevValue = *value; // Progress bar Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), @@ -3496,6 +3567,8 @@ int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight // WARNING: Working with floats could lead to rounding issues if ((state != STATE_DISABLED)) progress.width = ((float)*value/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)); + + if (prevValue != *value) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3566,9 +3639,26 @@ int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight // Status Bar control int GuiStatusBar(Rectangle bounds, const char *text) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check checkbox state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + //if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + //else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; + } + } + //-------------------------------------------------------------------- + // Draw control //-------------------------------------------------------------------- GuiDrawRectangle(bounds, GuiGetStyle(STATUSBAR, BORDER_WIDTH), GetColor(GuiGetStyle(STATUSBAR, BORDER + (state*3))), GetColor(GuiGetStyle(STATUSBAR, BASE + (state*3)))); @@ -3581,7 +3671,7 @@ int GuiStatusBar(Rectangle bounds, const char *text) // Dummy rectangle control, intended for placeholding int GuiDummyRec(Rectangle bounds, const char *text) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Update control @@ -3595,6 +3685,8 @@ int GuiDummyRec(Rectangle bounds, const char *text) { if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; } } //-------------------------------------------------------------------- @@ -3611,25 +3703,26 @@ int GuiDummyRec(Rectangle bounds, const char *text) // List View control int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active) { - int result = 0; + int result = RESULT_NONE; int itemCount = 0; char **items = NULL; - if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL); + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount); result = GuiListViewEx(bounds, items, itemCount, scrollIndex, active, NULL); return result; } -// List View control with extended parameters +// List View control using text entries list and returning focus entry int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; int itemFocused = (focus == NULL)? -1 : *focus; int itemSelected = (active == NULL)? -1 : *active; + int prevActive = (active == NULL)? 0 : *active; // Check if scroll bar is needed bool useScrollBar = false; @@ -3767,35 +3860,132 @@ int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, in if (focus != NULL) *focus = itemFocused; if (scrollIndex != NULL) *scrollIndex = startIndex; + if (prevActive != *active) result = RESULT_CHANGED; + return result; } -// Color Panel control - Color (RGBA) variant +// Tab Bar control +int GuiTabBar(Rectangle bounds, const char *text, int *hscroll, int *active) +{ + int result = RESULT_NONE; + int itemCount = 0; + char **items = NULL; + + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount); + + result = GuiTabBarEx(bounds, items, itemCount, hscroll, active, NULL); + + return result; +} + +// Tab Bar control, using text entries list and returning focus entry +// NOTE: In case of tab close result, consider focused tab +// TODO: Reeplace GuiToggle() usage for custom implementation for the TABS +int GuiTabBarEx(Rectangle bounds, char **text, int count, int *hscroll, int *active, int *focus) +{ + int result = RESULT_NONE; + //GuiState state = guiState; + + int tabItemsWidth = GuiGetStyle(TABBAR, TAB_ITEMS_WIDTH); + Rectangle tabBounds = { bounds.x, bounds.y, (float)tabItemsWidth, bounds.height }; + + if (*active < 0) *active = 0; + else if (*active > count - 1) *active = count - 1; + + int prevActive = (active == NULL)? 0 : *active; + + int offsetX = 0; // Required in case tabs go out of screen + offsetX = (*active*tabItemsWidth) - GetScreenWidth(); + if (offsetX < 0) offsetX = 0; + + bool toggle = false; // Required for individual toggles + + // Draw control + //-------------------------------------------------------------------- + //if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) // TODO: Support disabled + + for (int i = 0; i < count; i++) + { + tabBounds.x = bounds.x + (tabItemsWidth + 4)*i + offsetX; + + if (tabBounds.x < GetScreenWidth()) + { + // Draw tabs as toggle controls + int textAlignment = GuiGetStyle(TOGGLE, TEXT_ALIGNMENT); + int textPadding = GuiGetStyle(TOGGLE, TEXT_PADDING); + GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(TOGGLE, TEXT_PADDING, 8); + + if (i == (*active)) + { + toggle = true; + GuiToggle(tabBounds, text[i], &toggle); + } + else + { + toggle = false; + GuiToggle(tabBounds, text[i], &toggle); + if (toggle) *active = i; + } + + // Close tab with middle mouse button pressed + if (CheckCollisionPointRec(GUI_POINTER_POSITION, tabBounds) && GUI_BUTTON_PRESSED_MID) result = RESULT_TAB_CLOSE; + + GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding); + GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment); + + if (GuiGetStyle(TABBAR, TAB_CLOSE_BUTTON)) + { + // Draw tab close button + // NOTE: Only draw close button for current tab: if (CheckCollisionPointRec(mousePosition, tabBounds)) + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 1); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); +#if defined(RAYGUI_NO_ICONS) + if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, "x")) result = RESULT_TAB_CLOSE; +#else + if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, + GuiIconText(ICON_CROSS_SMALL, NULL))) result = RESULT_TAB_CLOSE; +#endif + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); + } + } + } + + // Draw tab-bar bottom line + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, 1 }, 0, BLANK, GetColor(GuiGetStyle(TABBAR, BORDER_COLOR_NORMAL))); + //-------------------------------------------------------------------- + + // NOTE: In case of tab close result, consider focused tab + if ((result != RESULT_TAB_CLOSE) && (prevActive != *active)) result = RESULT_CHANGED; + + return result; +} + +// Color Panel control int GuiColorPanel(Rectangle bounds, const char *text, Color *color) { - int result = 0; + int result = RESULT_NONE; Vector3 vcolor = { (float)color->r/255.0f, (float)color->g/255.0f, (float)color->b/255.0f }; Vector3 hsv = ConvertRGBtoHSV(vcolor); - Vector3 prevHsv = hsv; // workaround to see if GuiColorPanelHSV modifies the hsv + Vector3 prevHsv = hsv; // NOTE: Workaround to see if GuiColorPanelHSV() modifies the hsv - GuiColorPanelHSV(bounds, text, &hsv); + result = GuiColorPanelHSV(bounds, text, &hsv); // Check if the hsv was changed, only then change the color // This is required, because the Color->HSV->Color conversion has precision errors // Thus the assignment from HSV to Color should only be made, if the HSV has a new user-entered value // Otherwise GuiColorPanel would often modify it's color without user input - // TODO: GuiColorPanelHSV could return 1 if the slider was dragged, to simplify this check - if (hsv.x != prevHsv.x || hsv.y != prevHsv.y || hsv.z != prevHsv.z) + if ((hsv.x != prevHsv.x) || (hsv.y != prevHsv.y) || (hsv.z != prevHsv.z)) { Vector3 rgb = ConvertHSVtoRGB(hsv); - - // NOTE: Vector3ToColor() only available on raylib 1.8.1 - *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x), - (unsigned char)(255.0f*rgb.y), - (unsigned char)(255.0f*rgb.z), - color->a }; + *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x), (unsigned char)(255.0f*rgb.y), (unsigned char)(255.0f*rgb.z), color->a }; } + return result; } @@ -3807,8 +3997,10 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) #define RAYGUI_COLORBARALPHA_CHECKED_SIZE 10 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; + + float prevAlpha = *alpha; Rectangle selector = { (float)bounds.x + (*alpha)*bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.y - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT), @@ -3855,6 +4047,8 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) else state = STATE_FOCUSED; } } + + if (prevAlpha != *alpha) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3895,8 +4089,10 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) // float GuiColorBarLuminance() [BLACK->WHITE] int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; + + float prevHue = *hue; Rectangle selector = { (float)bounds.x - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)bounds.y + (*hue)/360.0f*bounds.height - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2, (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT) }; // Update control @@ -3951,6 +4147,8 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) }*/ } } + + if (prevHue != *hue) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3958,15 +4156,32 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) if (state != STATE_DISABLED) { // Draw hue bar:color bars - // TODO: Use directly DrawRectangleGradientEx(bounds, color1, color2, color2, color1); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + bounds.height/6), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 2*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 3*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 4*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 5*(bounds.height/6)), (int)bounds.width, (int)(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha)); + // NOTE: Using DrawRectangleGradientEx(bounds, color1, color2, color2, color1); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 1*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 2*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 3*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 4*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 5*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha)); + } + else + { + DrawRectangleGradientEx(bounds, + Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), + Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha)); } - else DrawRectangleGradientV((int)bounds.x, (int)bounds.y, (int)bounds.width, (int)bounds.height, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha)); GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); @@ -3986,12 +4201,12 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) // NOTE: this picker converts RGB to HSV, which can cause the Hue control to jump. If you have this problem, consider using the HSV variant instead int GuiColorPicker(Rectangle bounds, const char *text, Color *color) { - int result = 0; + int result = RESULT_NONE; Color temp = { 200, 0, 0, 255 }; if (color == NULL) color = &temp; - GuiColorPanel(bounds, NULL, color); + result = GuiColorPanel(bounds, NULL, color); Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; //Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) }; @@ -3999,7 +4214,7 @@ int GuiColorPicker(Rectangle bounds, const char *text, Color *color) // NOTE: this conversion can cause low hue-resolution, if the r, g and b value are very similar, which causes the hue bar to shift around when only the GuiColorPanel is used Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ (*color).r/255.0f, (*color).g/255.0f, (*color).b/255.0f }); - GuiColorBarHue(boundsHue, NULL, &hsv.x); + if (result != RESULT_CHANGED) result = GuiColorBarHue(boundsHue, NULL, &hsv.x); //color.a = (unsigned char)(GuiColorBarAlpha(boundsAlpha, (float)color.a/255.0f)*255.0f); Vector3 rgb = ConvertHSVtoRGB(hsv); @@ -4018,7 +4233,7 @@ int GuiColorPicker(Rectangle bounds, const char *text, Color *color) // NOTE: bounds define GuiColorPanelHSV() size int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) { - int result = 0; + int result = RESULT_NONE; Vector3 tempHsv = { 0 }; @@ -4029,11 +4244,11 @@ int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) colorHsv = &tempHsv; } - GuiColorPanelHSV(bounds, NULL, colorHsv); + result = GuiColorPanelHSV(bounds, NULL, colorHsv); - const Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; + Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; - GuiColorBarHue(boundsHue, NULL, &colorHsv->x); + if (result == RESULT_NONE) result = GuiColorBarHue(boundsHue, NULL, &colorHsv->x); return result; } @@ -4041,10 +4256,11 @@ int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) // Color Panel control - HSV variant int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; - Vector2 pickerSelector = { 0 }; + Vector3 prevColorHsv = *colorHsv; + Vector2 pickerSelector = { 0 }; const Color colWhite = { 255, 255, 255, 255 }; const Color colBlack = { 0, 0, 0, 255 }; @@ -4053,9 +4269,7 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) Vector3 maxHue = { colorHsv->x, 1.0f, 1.0f }; Vector3 rgbHue = ConvertHSVtoRGB(maxHue); - Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x), - (unsigned char)(255.0f*rgbHue.y), - (unsigned char)(255.0f*rgbHue.z), 255 }; + Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x), (unsigned char)(255.0f*rgbHue.y), (unsigned char)(255.0f*rgbHue.z), 255 }; // Update control //-------------------------------------------------------------------- @@ -4079,12 +4293,11 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) // Calculate color from picker Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y }; - colorPick.x /= (float)bounds.width; // Get normalized value on x - colorPick.y /= (float)bounds.height; // Get normalized value on y + colorPick.x /= (float)bounds.width; // Get normalized value on x + colorPick.y /= (float)bounds.height; // Get normalized value on y colorHsv->y = colorPick.x; colorHsv->z = 1.0f - colorPick.y; - } } else @@ -4114,6 +4327,10 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) else state = STATE_FOCUSED; } } + + if ((prevColorHsv.x != colorHsv->x) || + (prevColorHsv.y != colorHsv->y) || + (prevColorHsv.z != colorHsv->z)) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -4139,7 +4356,8 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) } // Message Box control -int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons) +// NOTE: Button pressed is returned through btnActive parameter, 0 for window close button +int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *btnText, int *btnActive) { #if !defined(RAYGUI_MESSAGEBOX_BUTTON_HEIGHT) #define RAYGUI_MESSAGEBOX_BUTTON_HEIGHT 24 @@ -4148,10 +4366,10 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons #define RAYGUI_MESSAGEBOX_BUTTON_PADDING 12 #endif - int result = -1; // Returns clicked button from buttons list, 0 refers to closed window button + int result = RESULT_NONE; int buttonCount = 0; - char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL); + char **btnTextList = GuiTextSplit(btnText, ';', &buttonCount); Rectangle buttonBounds = { 0 }; buttonBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING; buttonBounds.y = bounds.y + bounds.height - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT - RAYGUI_MESSAGEBOX_BUTTON_PADDING; @@ -4168,7 +4386,11 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons // Draw control //-------------------------------------------------------------------- - if (GuiWindowBox(bounds, title)) result = 0; + if (GuiWindowBox(bounds, title) == RESULT_PRESSED) + { + *btnActive = 0; + result = RESULT_PRESSED; + } int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); @@ -4180,7 +4402,11 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons for (int i = 0; i < buttonCount; i++) { - if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1; + if (GuiButton(buttonBounds, btnTextList[i])) + { + *btnActive = i + 1; + result = RESULT_PRESSED; + } buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING); } @@ -4190,8 +4416,9 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons return result; } -// Text Input Box control, ask for text -int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive) +// Text Input Box control +// NOTE: Button pressed is returned through btnActive parameter, 0 for window close button +int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, char *text, int textSize, const char *btnText, int *btnActive, bool *secretViewActive) { #if !defined(RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT) #define RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT 24 @@ -4203,14 +4430,14 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co #define RAYGUI_TEXTINPUTBOX_HEIGHT 26 #endif + int result = RESULT_NONE; + // Used to enable text edit mode // WARNING: No more than one GuiTextInputBox() should be open at the same time static bool textEditMode = false; - int result = -1; - int buttonCount = 0; - char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL); + char **btnTextList = GuiTextSplit(btnText, ';', &buttonCount); Rectangle buttonBounds = { 0 }; buttonBounds.x = bounds.x + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; buttonBounds.y = bounds.y + bounds.height - RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; @@ -4240,7 +4467,11 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co // Draw control //-------------------------------------------------------------------- - if (GuiWindowBox(bounds, title)) result = 0; + if (GuiWindowBox(bounds, title) == RESULT_PRESSED) + { + *btnActive = 0; + result = RESULT_PRESSED; + } // Draw message if available if (message != NULL) @@ -4258,13 +4489,20 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co { static char stars[] = "****************"; if (GuiTextBox(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x, textBoxBounds.y, textBoxBounds.width - 4 - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.height }, - ((*secretViewActive == 1) || textEditMode)? text : stars, textMaxSize, textEditMode)) textEditMode = !textEditMode; + ((*secretViewActive == 1) || textEditMode)? text : stars, textSize, textEditMode) == RESULT_PRESSED) textEditMode = !textEditMode; - GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, (*secretViewActive == 1)? "#44#" : "#45#", secretViewActive); +#if defined(RAYGUI_NO_ICONS) + GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, + (*secretViewActive == 1)? "O" : "*", secretViewActive); +#else + GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, + (*secretViewActive == 1)? GuiIconText(ICON_EYE_ON, NULL) : GuiIconText(ICON_EYE_OFF, NULL), secretViewActive); +#endif } else { - if (GuiTextBox(textBoxBounds, text, textMaxSize, textEditMode)) textEditMode = !textEditMode; + if (GuiTextBox(textBoxBounds, text, textSize, textEditMode) == RESULT_PRESSED) + textEditMode = !textEditMode; } GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, prevTextBoxAlignment); @@ -4274,16 +4512,21 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co for (int i = 0; i < buttonCount; i++) { - if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1; + if (GuiButton(buttonBounds, btnTextList[i])) + { + *btnActive = i + 1; + result = RESULT_PRESSED; + } + buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING); } - if (result >= 0) textEditMode = false; + if (result == RESULT_PRESSED) textEditMode = false; GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevBtnTextAlignment); //-------------------------------------------------------------------- - return result; // Result is the pressed button index + return result; } // Grid control @@ -4297,7 +4540,7 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect #define RAYGUI_GRID_ALPHA 0.15f #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; Vector2 mousePoint = GUI_POINTER_POSITION; @@ -4318,6 +4561,8 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect // NOTE: Cell values must be the upper left of the cell the mouse is in currentMouseCell.x = floorf((mousePoint.x - bounds.x)/spacing); currentMouseCell.y = floorf((mousePoint.y - bounds.y)/spacing); + + result = RESULT_PRESSED; } } //-------------------------------------------------------------------- @@ -4344,6 +4589,7 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect } if (mouseCell != NULL) *mouseCell = currentMouseCell; + return result; } @@ -4387,11 +4633,16 @@ void GuiLoadStyle(const char *fileName) int controlId = 0; int propertyId = 0; unsigned int propertyValue = 0; + unsigned int version = 0; while (!feof(rgsFile)) { switch (buffer[0]) { + case 'v': + { + sscanf(buffer, "v %d", &version); + } case 'p': { // Style property: p @@ -4402,12 +4653,17 @@ void GuiLoadStyle(const char *fileName) } break; case 'f': { - // Style font: f + // Style font: f int fontSize = 0; - char charmapFileName[256] = { 0 }; - char fontFileName[256] = { 0 }; - sscanf(buffer, "f %d %s %[^\r\n]s", &fontSize, charmapFileName, fontFileName); + char charmapFileName[32] = { 0 }; + char fontFileName[32] = { 0 }; + + if (version >= 600) sscanf(buffer, "f %d %31s %31[^\r\n]s", &fontSize, fontFileName, charmapFileName); + else sscanf(buffer, "f %d %31s %31[^\r\n]s", &fontSize, charmapFileName, fontFileName); + + // GLOBAL: Copy font file name into guiFontName + snprintf(guiFontName, 32, "%s", fontFileName); Font font = { 0 }; int *codepoints = NULL; @@ -4483,6 +4739,318 @@ void GuiLoadStyle(const char *fileName) } } +// Load style from memory +// WARNING: Binary files only +void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize) +{ + // Style File Structure (.rgs) + // ------------------------------------------------------ + // Offset | Size | Type | Description + // ------------------------------------------------------ + // 0 | 4 | char | Signature: "rGS " + // 4 | 2 | short | Version: 200, 400, 600 + // 6 | 2 | short | reserved + // 8 | 4 | int | Num properties (only changed ones from default style) + + // Properties Data (8 bytes per property) + // WARNING: Only properties required that differ from default (light) internal style + // foreach (property) + // { + // 8+8*i | 2 | short | ControlId + // 8+8*i | 2 | short | PropertyId + // 8+8*i | 4 | int | PropertyValue + // } + + // Custom Font Data : Parameters (64 bytes) + // ... | 4 | int | Font data size (0 - no font, no more fields added!) + // ... | 32 | char | Font filename (with extension) - VERSION: >=600 + // ... | 4 | int | Font base size + // ... | 4 | int | Font glyph count [glyphCount] + // ... | 4 | int | Font type (0-NORMAL, 1-SDF) + // ... | 16 | Rectangle | Font white rectangle + + // Custom Font Data : Image (20 bytes + imData) + // NOTE: Font image atlas is always converted to GRAY+ALPHA + // and atlas image data can be compressed (DEFLATE) + // ... | 4 | int | Image data size (uncompressed) + // ... | 4 | int | Image data size (compressed) + // ... | 4 | int | Image width + // ... | 4 | int | Image height + // ... | 4 | int | Image format: GRAY+ALPHA (expected) + // ... | imSize | byte | Image data (comp or uncomp) + + // Custom Font Data : Recs (32 bytes*glyphCount) + // NOTE: Font recs data can be compressed (DEFLATE) + // ... | 4 | int | Recs data compressed size (0 - not compressed, 1-compressed) - VERSION: >=400 + // + // if (compRecsSize == 0) + // { + // NOTE: Uncompressed size can be calculated: (glyphCount*16 byte) + // foreach (glyph) + // { + // ... | 16 | Rectangle | Glyph rectangle (in image) + // } + // } + // else + // { + // ... | compRecsSize | byte | Rectangles data + // } + // + + // Custom Font Data : Glyph Info (32 bytes*glyphCount) + // NOTE: Font glyphs info data can be compressed (DEFLATE) + // ... | 4 | int | Glyphs data compressed size (0 - not compressed) - VERSION: >=400 + // + // if (compGlyphsSize == 0) + // { + // NOTE: Uncompressed size can be calculated: (glyphCount*16 byte) + // foreach (glyph) + // { + // ... | 4 | int | Glyph value + // ... | 4 | int | Glyph offset X + // ... | 4 | int | Glyph offset Y + // ... | 4 | int | Glyph advance X + // } + // } + // else + // { + // ... | compGlyphsSize | byte | Glyphs data + // } + // ------------------------------------------------------ + + unsigned char *fileDataPtr = (unsigned char *)fileData; + + char signature[5] = { 0 }; + short version = 0; + short reserved = 0; + int propertyCount = 0; + + memcpy(signature, fileDataPtr, 4); + memcpy(&version, fileDataPtr + 4, sizeof(short)); + memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short)); + memcpy(&propertyCount, fileDataPtr + 4 + 2 + 2, sizeof(int)); + fileDataPtr += 12; + + if ((signature[0] == 'r') && + (signature[1] == 'G') && + (signature[2] == 'S') && + (signature[3] == ' ')) + { + short controlId = 0; + short propertyId = 0; + unsigned int propertyValue = 0; + + for (int i = 0; i < propertyCount; i++) + { + memcpy(&controlId, fileDataPtr, sizeof(short)); + memcpy(&propertyId, fileDataPtr + 2, sizeof(short)); + memcpy(&propertyValue, fileDataPtr + 2 + 2, sizeof(unsigned int)); + fileDataPtr += 8; + + if (controlId == 0) // DEFAULT control + { + // If a DEFAULT property is loaded, it is propagated to all controls + // NOTE: All DEFAULT properties should be defined first in the file + GuiSetStyle(0, (int)propertyId, propertyValue); + + if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int j = 1; j < RAYGUI_MAX_CONTROLS; j++) GuiSetStyle(j, (int)propertyId, propertyValue); + } + else GuiSetStyle((int)controlId, (int)propertyId, propertyValue); + } + + // Load custom font if available + // NOTE: Font texture loading requires raylib + int fontDataSize = 0; + memcpy(&fontDataSize, fileDataPtr, sizeof(int)); + fileDataPtr += 4; + + if (fontDataSize > 0) + { + Font font = { 0 }; + int fontType = 0; // 0-Normal, 1-SDF + + // WARNING: Version 600 adds 32 bytes for the font filename (with extension) + if (version >= 600) + { + // GLOBAL: Copy font file name into guiFontName + memcpy(guiFontName, fileDataPtr, 32); + fileDataPtr += 32; + } + else memset(guiFontName, 0, 32); + + memcpy(&font.baseSize, fileDataPtr, sizeof(int)); + memcpy(&font.glyphCount, fileDataPtr + 4, sizeof(int)); + memcpy(&fontType, fileDataPtr + 4 + 4, sizeof(int)); + fileDataPtr += 12; + + // Load font white rectangle + Rectangle fontWhiteRec = { 0 }; + memcpy(&fontWhiteRec, fileDataPtr, sizeof(Rectangle)); + fileDataPtr += 16; + + // Load font image parameters + int fontImageUncompSize = 0; + int fontImageCompSize = 0; + memcpy(&fontImageUncompSize, fileDataPtr, sizeof(int)); + memcpy(&fontImageCompSize, fileDataPtr + 4, sizeof(int)); + fileDataPtr += 8; + + Image imFont = { 0 }; + imFont.mipmaps = 1; + memcpy(&imFont.width, fileDataPtr, sizeof(int)); + memcpy(&imFont.height, fileDataPtr + 4, sizeof(int)); + memcpy(&imFont.format, fileDataPtr + 4 + 4, sizeof(int)); + fileDataPtr += 12; + + if ((fontImageCompSize > 0) && (fontImageCompSize != fontImageUncompSize)) + { + // Compressed font atlas image data (DEFLATE), it requires DecompressData() + int dataUncompSize = 0; + unsigned char *compData = (unsigned char *)RAYGUI_CALLOC(fontImageCompSize, sizeof(unsigned char)); + memcpy(compData, fileDataPtr, fontImageCompSize); + fileDataPtr += fontImageCompSize; + + imFont.data = DecompressData(compData, fontImageCompSize, &dataUncompSize); + + // Security check, dataUncompSize must match the provided fontImageUncompSize + if (dataUncompSize != fontImageUncompSize) RAYGUI_LOG("WARNING: Uncompressed font atlas image data could be corrupted"); + + RAYGUI_FREE(compData); + } + else + { + // Font atlas image data is not compressed + imFont.data = (unsigned char *)RAYGUI_CALLOC(fontImageUncompSize, sizeof(unsigned char)); + memcpy(imFont.data, fileDataPtr, fontImageUncompSize); + fileDataPtr += fontImageUncompSize; + } + + // Load font recs data (glyphs position and size in the image atlas) + int recsDataSize = font.glyphCount*sizeof(Rectangle); + int recsDataCompressedSize = 0; + + // WARNING: Version 400 adds the compression size parameter + if (version >= 400) + { + // RGS files version 400 support compressed recs data + memcpy(&recsDataCompressedSize, fileDataPtr, sizeof(int)); + fileDataPtr += sizeof(int); + } + + if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize)) + { + // Recs data is compressed, uncompress it + unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_CALLOC(recsDataCompressedSize, sizeof(unsigned char)); + + memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize); + fileDataPtr += recsDataCompressedSize; + + int recsDataUncompSize = 0; + font.recs = (Rectangle *)DecompressData(recsDataCompressed, recsDataCompressedSize, &recsDataUncompSize); + + // Security check, data uncompressed size must match the expected original data size + if (recsDataUncompSize != recsDataSize) RAYGUI_LOG("WARNING: Uncompressed font recs data could be corrupted"); + + RAYGUI_FREE(recsDataCompressed); + } + else + { + // Recs data is uncompressed + font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle)); + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.recs[i], fileDataPtr, sizeof(Rectangle)); + fileDataPtr += sizeof(Rectangle); + } + } + + // Load font glyphs info data + int glyphsDataSize = font.glyphCount*16; // 16 bytes data per glyph + int glyphsDataCompressedSize = 0; + + // WARNING: Version 400 adds the compression size parameter + if (version >= 400) + { + // RGS files version 400 support compressed glyphs data + memcpy(&glyphsDataCompressedSize, fileDataPtr, sizeof(int)); + fileDataPtr += sizeof(int); + } + + // Allocate required glyphs space to fill with data + font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo)); + + if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize)) + { + // Glyphs data is compressed, uncompress it + unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_CALLOC(glyphsDataCompressedSize, sizeof(unsigned char)); + + memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize); + fileDataPtr += glyphsDataCompressedSize; + + int glyphsDataUncompSize = 0; + unsigned char *glyphsDataUncomp = DecompressData(glypsDataCompressed, glyphsDataCompressedSize, &glyphsDataUncompSize); + + // Security check, data uncompressed size must match the expected original data size + if (glyphsDataUncompSize != glyphsDataSize) RAYGUI_LOG("WARNING: Uncompressed font glyphs data could be corrupted"); + + unsigned char *glyphsDataUncompPtr = glyphsDataUncomp; + + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.glyphs[i].value, glyphsDataUncompPtr, sizeof(int)); + memcpy(&font.glyphs[i].offsetX, glyphsDataUncompPtr + 4, sizeof(int)); + memcpy(&font.glyphs[i].offsetY, glyphsDataUncompPtr + 8, sizeof(int)); + memcpy(&font.glyphs[i].advanceX, glyphsDataUncompPtr + 12, sizeof(int)); + glyphsDataUncompPtr += 16; + } + + RAYGUI_FREE(glypsDataCompressed); + RAYGUI_FREE(glyphsDataUncomp); + } + else + { + // Glyphs data is uncompressed + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.glyphs[i].value, fileDataPtr, sizeof(int)); + memcpy(&font.glyphs[i].offsetX, fileDataPtr + 4, sizeof(int)); + memcpy(&font.glyphs[i].offsetY, fileDataPtr + 8, sizeof(int)); + memcpy(&font.glyphs[i].advanceX, fileDataPtr + 12, sizeof(int)); + fileDataPtr += 16; + } + } + +#if defined(RAYGUI_FONT_ICONS_BAKING) + // Font atlas image icons baking + Rectangle updatedWhiteRec = { 0 }; + guiIconFontOffsetY = GuiFontIconBaking(&imFont, font, &updatedWhiteRec); + if (guiIconFontOffsetY > 0) fontWhiteRec = updatedWhiteRec; +#endif + +#if !defined(RAYGUI_STANDALONE) + // Load texture from image + if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture); + font.texture = LoadTextureFromImage(imFont); + + // Fallback to default raylib texture if font texture loading fails + if (font.texture.id != 0) + { + // Set font texture source rectangle to be used as white texture to draw shapes + // NOTE: It makes possible to draw shapes and text (full UI) in a single draw call + if ((fontWhiteRec.x > 0) && + (fontWhiteRec.y > 0) && + (fontWhiteRec.width > 0) && + (fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec); + } + else font = GetFontDefault(); + + GuiSetFont(font); +#endif + RAYGUI_FREE(imFont.data); + } + } +} + // Load style default over global style void GuiLoadStyleDefault(void) { @@ -4515,7 +5083,7 @@ void GuiLoadStyleDefault(void) GuiSetStyle(DEFAULT, TEXT_SPACING, 1); // DEFAULT, shared by all controls GuiSetStyle(DEFAULT, LINE_COLOR, 0x90abb5ff); // DEFAULT specific property GuiSetStyle(DEFAULT, BACKGROUND_COLOR, 0xf5f5f5ff); // DEFAULT specific property - GuiSetStyle(DEFAULT, TEXT_LINE_SPACING, 5); // DEFAULT, pixels between lines, from bottom of first line to top of second + GuiSetStyle(DEFAULT, TEXT_LINE_SPACING, 12); // DEFAULT, pixels between lines, from bottom of first line to top of second GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); // DEFAULT, text aligned vertically to middle of text-bounds // Initialize control-specific property values @@ -4534,6 +5102,7 @@ void GuiLoadStyleDefault(void) GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); GuiSetStyle(STATUSBAR, TEXT_PADDING, 8); GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(TABBAR, TAB_ITEMS_WIDTH, 160); // Initialize extended property values // NOTE: By default, extended property values are initialized to 0 @@ -4583,6 +5152,9 @@ void GuiLoadStyleDefault(void) // NOTE: Setting up a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering SetShapesTexture(guiFont.texture, RAYGUI_CLITERAL(Rectangle){ whiteChar.x + 1, whiteChar.y + 1, whiteChar.width - 2, whiteChar.height - 2 }); + + // Reset baked icons offset in font + guiIconFontOffsetY = 0; } } @@ -4624,71 +5196,28 @@ const char *GuiIconText(int iconId, const char *text) unsigned int *GuiGetIcons(void) { return guiIconsPtr; } // Load raygui icons file (.rgi) -// NOTE: In case nameIds are required, they can be requested with loadIconsName, -// they are returned as a guiIconsName[iconCount][RAYGUI_ICON_MAX_NAME_LENGTH], // WARNING: guiIconsName[]][] memory should be manually freed! char **GuiLoadIcons(const char *fileName, bool loadIconsName) { - // Style File Structure (.rgi) - // ------------------------------------------------------ - // Offset | Size | Type | Description - // ------------------------------------------------------ - // 0 | 4 | char | Signature: "rGI " - // 4 | 2 | short | Version: 100 - // 6 | 2 | short | reserved - - // 8 | 2 | short | Num icons (N) - // 10 | 2 | short | Icons size (Options: 16, 32, 64) (S) - - // Icons name id (32 bytes per name id) - // foreach (icon) - // { - // 12+32*i | 32 | char | Icon NameId - // } - - // Icons data: One bit per pixel, stored as unsigned int array (depends on icon size) - // S*S pixels/32bit per unsigned int = K unsigned int per icon - // foreach (icon) - // { - // ... | K | unsigned int | Icon Data - // } - FILE *rgiFile = fopen(fileName, "rb"); - char **guiIconsName = NULL; if (rgiFile != NULL) { - char signature[5] = { 0 }; - short version = 0; - short reserved = 0; - short iconCount = 0; - short iconSize = 0; + unsigned char *fileData = NULL; + int dataSize = 0; - fread(signature, 1, 4, rgiFile); - fread(&version, sizeof(short), 1, rgiFile); - fread(&reserved, sizeof(short), 1, rgiFile); - fread(&iconCount, sizeof(short), 1, rgiFile); - fread(&iconSize, sizeof(short), 1, rgiFile); + fseek(rgiFile, 0, SEEK_END); + int size = (int)ftell(rgiFile); + fseek(rgiFile, 0, SEEK_SET); - if ((signature[0] == 'r') && - (signature[1] == 'G') && - (signature[2] == 'I') && - (signature[3] == ' ')) + if (size > 0) { - if (loadIconsName) - { - guiIconsName = (char **)RAYGUI_CALLOC(iconCount, sizeof(char *)); - for (int i = 0; i < iconCount; i++) - { - guiIconsName[i] = (char *)RAYGUI_CALLOC(RAYGUI_ICON_MAX_NAME_LENGTH, sizeof(char)); - fread(guiIconsName[i], 1, RAYGUI_ICON_MAX_NAME_LENGTH, rgiFile); - } - } - else fseek(rgiFile, iconCount*RAYGUI_ICON_MAX_NAME_LENGTH, SEEK_CUR); + fileData = (unsigned char *)RL_CALLOC(size, sizeof(unsigned char)); + // WARNING: File can be partially loaded but ignoring it for simplicity + dataSize = (int)fread(fileData, sizeof(unsigned char), size, rgiFile); - // Read icons data directly over internal icons array - fread(guiIconsPtr, sizeof(unsigned int), (int)iconCount*((int)iconSize*(int)iconSize/32), rgiFile); + guiIconsName = GuiLoadIconsFromMemory(fileData, dataSize, loadIconsName); } fclose(rgiFile); @@ -4698,9 +5227,34 @@ char **GuiLoadIcons(const char *fileName, bool loadIconsName) } // Load icons from memory -// WARNING: Binary files only +// GLOBAL: Updates global variable: guiIconsPtr char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName) { + // Icon File Structure (.rgi) + // ------------------------------------------------------ + // Offset | Size | Type | Description + // ------------------------------------------------------ + // 0 | 4 | char | Signature: "rGI " + // 4 | 2 | short | Version: 100, 500 + // 6 | 2 | short | reserved + + // 8 | 2 | short | Num icons (N) + // 10 | 2 | short | Icons Size (Options: 16, 32, 64) + + // Icons name id (32 bytes per name id) + // foreach (icon) + // { + // 12+32*i | 32 | char | Icon NameId + // } + + // Icons data: One bit per pixel, stored as unsigned int array (depends on icon size) + // Size*Size pixels/32bit per unsigned int = K unsigned int per icon + // foreach (icon) + // { + // ... | K | unsigned int | Icon Data + // } + // ------------------------------------------------------ + unsigned char *fileDataPtr = (unsigned char *)fileData; char **guiIconsName = NULL; @@ -4724,7 +5278,8 @@ char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool { if (loadIconsName) { - guiIconsName = (char **)RAYGUI_CALLOC(iconCount, sizeof(char *)); + // NOTE: Always allocating RAYGUI_ICON_MAX_ICONS names slots + guiIconsName = (char **)RAYGUI_CALLOC(RAYGUI_ICON_MAX_ICONS, sizeof(char *)); for (int i = 0; i < iconCount; i++) { guiIconsName[i] = (char *)RAYGUI_CALLOC(RAYGUI_ICON_MAX_NAME_LENGTH, sizeof(char)); @@ -4750,20 +5305,35 @@ char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool // Draw selected icon using rectangles pixel-by-pixel void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color) { - #define BIT_CHECK(a,b) ((a) & (1u<<(b))) - - for (int i = 0, y = 0; i < RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32; i++) + if ((guiIconFontOffsetY > 0) && (iconId < RAYGUI_ICON_MAX_FONT_BACKED)) { - for (int k = 0; k < 32; k++) - { - if (BIT_CHECK(guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i], k)) - { - #if !defined(RAYGUI_STANDALONE) - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize, (float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color); - #endif - } + int maxIconsPerLine = guiFont.texture.width/(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + int x = iconId%maxIconsPerLine; + int y = iconId/maxIconsPerLine; - if ((k == 15) || (k == 31)) y++; + Rectangle srcRec = { (float)x*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + RAYGUI_ICON_FONT_ATLAS_PADDING, + guiIconFontOffsetY + (float)y*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + RAYGUI_ICON_FONT_ATLAS_PADDING, + RAYGUI_ICON_SIZE, RAYGUI_ICON_SIZE }; + Rectangle dstRec = { (float)posX, (float)posY, (float)pixelSize*RAYGUI_ICON_SIZE, (float)pixelSize*RAYGUI_ICON_SIZE }; + + DrawTexturePro(guiFont.texture, srcRec, dstRec, RAYGUI_CLITERAL(Vector2){ 0, 0 }, 0.0f, color); + } + else + { + #define BIT_CHECK(a,b) ((a) & (1u<<(b))) + + for (int i = 0, y = 0; i < RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32; i++) + { + for (int k = 0; k < 32; k++) + { + if (BIT_CHECK(guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i], k)) + { + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize, + (float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color); + } + + if ((k == 15) || (k == 31)) y++; + } } } } @@ -4774,28 +5344,56 @@ void GuiSetIconScale(int scale) if (scale >= 1) guiIconScale = scale; } -// Get text width considering gui style and icon size (if required) +// Get text width considering gui style and icon size (if required). +// For multi-line text (containing '\n'), returns the width of the widest line. int GuiGetTextWidth(const char *text) { - #if !defined(ICON_TEXT_PADDING) - #define ICON_TEXT_PADDING 4 - #endif + if (text == NULL) return 0; + + int maxWidth = 0; + const char *linePtr = text; + + while ((linePtr[0] != '\0') && ((linePtr - text) < MAX_LINE_BUFFER_SIZE)) + { + int lineWidth = GetLineWidth(linePtr); + if (lineWidth > maxWidth) maxWidth = lineWidth; + + // Skip to the next '\n' (or end of string/buffer) + while ((linePtr[0] != '\0') && (linePtr[0] != '\n') && ((linePtr - text) < MAX_LINE_BUFFER_SIZE)) + { + linePtr++; + } + // Advance past the '\n' delimiter to the start of the next line + if (linePtr[0] == '\n') linePtr++; + } + + return maxWidth; +} + +#endif // !RAYGUI_NO_ICONS + +//---------------------------------------------------------------------------------- +// Module Internal Functions Definition +//---------------------------------------------------------------------------------- +// Get text line width (stops at '\n' or '\0') +// NOTE: Considers icon marker '#NNN#' +static int GetLineWidth(const char *text) +{ +#if !defined(RAYGUI_ICON_TEXT_PADDING) + #define RAYGUI_ICON_TEXT_PADDING 4 +#endif Vector2 textSize = { 0 }; int textIconOffset = 0; if ((text != NULL) && (text[0] != '\0')) { + // Icon marker: '#' + 1..3 digits + '#' (matches GetTextIcon()) if (text[0] == '#') { - for (int i = 1; (i < 5) && (text[i] != '\0'); i++) - { - if (text[i] == '#') - { - textIconOffset = i; - break; - } - } + int pos = 1; + while ((pos < 4) && (text[pos] >= '0') && (text[pos] <= '9')) pos++; + if (text[pos] == '#') textIconOffset = pos + 1; } text += textIconOffset; @@ -4803,10 +5401,10 @@ int GuiGetTextWidth(const char *text) // Make sure guiFont is set, GuiGetStyle() initializes it lazynessly float fontSize = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - // Custom MeasureText() implementation + // Custom MeasureText() implementation -- single line only if ((guiFont.texture.id > 0) && (text != NULL)) { - // Get size in bytes of text, considering end of line and line break + // Get size in bytes of the line, considering end of line and line break int size = 0; for (int i = 0; i < MAX_LINE_BUFFER_SIZE; i++) { @@ -4830,239 +5428,12 @@ int GuiGetTextWidth(const char *text) } } - if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + ICON_TEXT_PADDING); + if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + RAYGUI_ICON_TEXT_PADDING); } return (int)textSize.x; } -#endif // !RAYGUI_NO_ICONS - -//---------------------------------------------------------------------------------- -// Module Internal Functions Definition -//---------------------------------------------------------------------------------- -// Load style from memory -// WARNING: Binary files only -static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize) -{ - unsigned char *fileDataPtr = (unsigned char *)fileData; - - char signature[5] = { 0 }; - short version = 0; - short reserved = 0; - int propertyCount = 0; - - memcpy(signature, fileDataPtr, 4); - memcpy(&version, fileDataPtr + 4, sizeof(short)); - memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short)); - memcpy(&propertyCount, fileDataPtr + 4 + 2 + 2, sizeof(int)); - fileDataPtr += 12; - - if ((signature[0] == 'r') && - (signature[1] == 'G') && - (signature[2] == 'S') && - (signature[3] == ' ')) - { - short controlId = 0; - short propertyId = 0; - unsigned int propertyValue = 0; - - for (int i = 0; i < propertyCount; i++) - { - memcpy(&controlId, fileDataPtr, sizeof(short)); - memcpy(&propertyId, fileDataPtr + 2, sizeof(short)); - memcpy(&propertyValue, fileDataPtr + 2 + 2, sizeof(unsigned int)); - fileDataPtr += 8; - - if (controlId == 0) // DEFAULT control - { - // If a DEFAULT property is loaded, it is propagated to all controls - // NOTE: All DEFAULT properties should be defined first in the file - GuiSetStyle(0, (int)propertyId, propertyValue); - - if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int j = 1; j < RAYGUI_MAX_CONTROLS; j++) GuiSetStyle(j, (int)propertyId, propertyValue); - } - else GuiSetStyle((int)controlId, (int)propertyId, propertyValue); - } - - // Font loading is highly dependant on raylib API to load font data and image - -#if !defined(RAYGUI_STANDALONE) - // Load custom font if available - int fontDataSize = 0; - memcpy(&fontDataSize, fileDataPtr, sizeof(int)); - fileDataPtr += 4; - - if (fontDataSize > 0) - { - Font font = { 0 }; - int fontType = 0; // 0-Normal, 1-SDF - - memcpy(&font.baseSize, fileDataPtr, sizeof(int)); - memcpy(&font.glyphCount, fileDataPtr + 4, sizeof(int)); - memcpy(&fontType, fileDataPtr + 4 + 4, sizeof(int)); - fileDataPtr += 12; - - // Load font white rectangle - Rectangle fontWhiteRec = { 0 }; - memcpy(&fontWhiteRec, fileDataPtr, sizeof(Rectangle)); - fileDataPtr += 16; - - // Load font image parameters - int fontImageUncompSize = 0; - int fontImageCompSize = 0; - memcpy(&fontImageUncompSize, fileDataPtr, sizeof(int)); - memcpy(&fontImageCompSize, fileDataPtr + 4, sizeof(int)); - fileDataPtr += 8; - - Image imFont = { 0 }; - imFont.mipmaps = 1; - memcpy(&imFont.width, fileDataPtr, sizeof(int)); - memcpy(&imFont.height, fileDataPtr + 4, sizeof(int)); - memcpy(&imFont.format, fileDataPtr + 4 + 4, sizeof(int)); - fileDataPtr += 12; - - if ((fontImageCompSize > 0) && (fontImageCompSize != fontImageUncompSize)) - { - // Compressed font atlas image data (DEFLATE), it requires DecompressData() - int dataUncompSize = 0; - unsigned char *compData = (unsigned char *)RAYGUI_CALLOC(fontImageCompSize, sizeof(unsigned char)); - memcpy(compData, fileDataPtr, fontImageCompSize); - fileDataPtr += fontImageCompSize; - - imFont.data = DecompressData(compData, fontImageCompSize, &dataUncompSize); - - // Security check, dataUncompSize must match the provided fontImageUncompSize - if (dataUncompSize != fontImageUncompSize) RAYGUI_LOG("WARNING: Uncompressed font atlas image data could be corrupted"); - - RAYGUI_FREE(compData); - } - else - { - // Font atlas image data is not compressed - imFont.data = (unsigned char *)RAYGUI_CALLOC(fontImageUncompSize, sizeof(unsigned char)); - memcpy(imFont.data, fileDataPtr, fontImageUncompSize); - fileDataPtr += fontImageUncompSize; - } - - if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture); - font.texture = LoadTextureFromImage(imFont); - - RAYGUI_FREE(imFont.data); - - // Validate font atlas texture was loaded correctly - if (font.texture.id != 0) - { - // Load font recs data - int recsDataSize = font.glyphCount*sizeof(Rectangle); - int recsDataCompressedSize = 0; - - // WARNING: Version 400 adds the compression size parameter - if (version >= 400) - { - // RGS files version 400 support compressed recs data - memcpy(&recsDataCompressedSize, fileDataPtr, sizeof(int)); - fileDataPtr += sizeof(int); - } - - if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize)) - { - // Recs data is compressed, uncompress it - unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_CALLOC(recsDataCompressedSize, sizeof(unsigned char)); - - memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize); - fileDataPtr += recsDataCompressedSize; - - int recsDataUncompSize = 0; - font.recs = (Rectangle *)DecompressData(recsDataCompressed, recsDataCompressedSize, &recsDataUncompSize); - - // Security check, data uncompressed size must match the expected original data size - if (recsDataUncompSize != recsDataSize) RAYGUI_LOG("WARNING: Uncompressed font recs data could be corrupted"); - - RAYGUI_FREE(recsDataCompressed); - } - else - { - // Recs data is uncompressed - font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle)); - for (int i = 0; i < font.glyphCount; i++) - { - memcpy(&font.recs[i], fileDataPtr, sizeof(Rectangle)); - fileDataPtr += sizeof(Rectangle); - } - } - - // Load font glyphs info data - int glyphsDataSize = font.glyphCount*16; // 16 bytes data per glyph - int glyphsDataCompressedSize = 0; - - // WARNING: Version 400 adds the compression size parameter - if (version >= 400) - { - // RGS files version 400 support compressed glyphs data - memcpy(&glyphsDataCompressedSize, fileDataPtr, sizeof(int)); - fileDataPtr += sizeof(int); - } - - // Allocate required glyphs space to fill with data - font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo)); - - if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize)) - { - // Glyphs data is compressed, uncompress it - unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_CALLOC(glyphsDataCompressedSize, sizeof(unsigned char)); - - memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize); - fileDataPtr += glyphsDataCompressedSize; - - int glyphsDataUncompSize = 0; - unsigned char *glyphsDataUncomp = DecompressData(glypsDataCompressed, glyphsDataCompressedSize, &glyphsDataUncompSize); - - // Security check, data uncompressed size must match the expected original data size - if (glyphsDataUncompSize != glyphsDataSize) RAYGUI_LOG("WARNING: Uncompressed font glyphs data could be corrupted"); - - unsigned char *glyphsDataUncompPtr = glyphsDataUncomp; - - for (int i = 0; i < font.glyphCount; i++) - { - memcpy(&font.glyphs[i].value, glyphsDataUncompPtr, sizeof(int)); - memcpy(&font.glyphs[i].offsetX, glyphsDataUncompPtr + 4, sizeof(int)); - memcpy(&font.glyphs[i].offsetY, glyphsDataUncompPtr + 8, sizeof(int)); - memcpy(&font.glyphs[i].advanceX, glyphsDataUncompPtr + 12, sizeof(int)); - glyphsDataUncompPtr += 16; - } - - RAYGUI_FREE(glypsDataCompressed); - RAYGUI_FREE(glyphsDataUncomp); - } - else - { - // Glyphs data is uncompressed - for (int i = 0; i < font.glyphCount; i++) - { - memcpy(&font.glyphs[i].value, fileDataPtr, sizeof(int)); - memcpy(&font.glyphs[i].offsetX, fileDataPtr + 4, sizeof(int)); - memcpy(&font.glyphs[i].offsetY, fileDataPtr + 8, sizeof(int)); - memcpy(&font.glyphs[i].advanceX, fileDataPtr + 12, sizeof(int)); - fileDataPtr += 16; - } - } - } - else font = GetFontDefault(); // Fallback in case of errors loading font atlas texture - - GuiSetFont(font); - - // Set font texture source rectangle to be used as white texture to draw shapes - // NOTE: It makes possible to draw shapes and text (full UI) in a single draw call - if ((fontWhiteRec.x > 0) && - (fontWhiteRec.y > 0) && - (fontWhiteRec.width > 0) && - (fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec); - } -#endif - } -} - // Get text bounds considering control bounds static Rectangle GetTextBounds(int control, Rectangle bounds) { @@ -5083,11 +5454,11 @@ static Rectangle GetTextBounds(int control, Rectangle bounds) case SLIDER: case CHECKBOX: case VALUEBOX: - case CONTROL11: - // TODO: More special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER + case TABBAR: + // TODO: Special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER default: { - // TODO: WARNING: TEXT_ALIGNMENT is already considered in GuiDrawText() + // WARNING: TEXT_ALIGNMENT is already considered in GuiDrawText() if (GuiGetStyle(control, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT) textBounds.x -= GuiGetStyle(control, TEXT_PADDING); else textBounds.x += GuiGetStyle(control, TEXT_PADDING); } @@ -5098,12 +5469,12 @@ static Rectangle GetTextBounds(int control, Rectangle bounds) } // Get text icon if provided and move text cursor -// NOTE: Up to #999# values supported for iconId +// NOTE: Up to RAYGUI_ICON_MAX_ICONS supported for iconId static const char *GetTextIcon(const char *text, int *iconId) { #if !defined(RAYGUI_NO_ICONS) *iconId = -1; - if (text[0] == '#') // Maybe it is stars with an icon, ending # must be found + if (text[0] == '#') // Maybe an icon, if it starts with # but an ending # must be found { char iconValue[4] = { 0 }; // Maximum length for icon value: 3 digits + '\0' @@ -5116,11 +5487,15 @@ static const char *GetTextIcon(const char *text, int *iconId) if (text[pos] == '#') { - *iconId = TextToInteger(iconValue); + int rawIconId = TextToInteger(iconValue); + if (rawIconId < RAYGUI_ICON_MAX_ICONS) + { + *iconId = rawIconId; - // Move text pointer after icon - // WARNING: If only icon provided, it could point to EOL character: '\0' - if (*iconId >= 0) text += (pos + 1); + // Move text pointer after icon + // WARNING: If only icon provided, it could point to EOL character: '\0' + if (*iconId >= 0) text += (pos + 1); + } } } #endif @@ -5188,8 +5563,8 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C { #define TEXT_VALIGN_PIXEL_OFFSET(h) ((int)h%2) // Vertical alignment for pixel perfect - #if !defined(ICON_TEXT_PADDING) - #define ICON_TEXT_PADDING 4 + #if !defined(RAYGUI_ICON_TEXT_PADDING) + #define RAYGUI_ICON_TEXT_PADDING 4 #endif if ((text == NULL) || (text[0] == '\0')) return; // Security check @@ -5225,9 +5600,9 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C Vector2 textBoundsPosition = { textBounds.x, textBounds.y }; float textBoundsWidthOffset = 0.0f; - // NOTE: Get text size after icon has been processed - // WARNING: GuiGetTextWidth() also processes text icon to get width! -> Really needed? - int textSizeX = GuiGetTextWidth(lines[i]); + // NOTE: Icon was already stripped above by GetTextIcon(); GetLineWidth() + // takes no icon path here and returns only the glyph width of this line. + int textSizeX = GetLineWidth(lines[i]); // If text requires an icon, add size to measure if (iconId >= 0) @@ -5236,7 +5611,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C // WARNING: If only icon provided, text could be pointing to EOF character: '\0' #if !defined(RAYGUI_NO_ICONS) - if ((lines[i] != NULL) && (lines[i][0] != '\0')) textSizeX += ICON_TEXT_PADDING; + if ((lines[i] != NULL) && (lines[i][0] != '\0')) textSizeX += RAYGUI_ICON_TEXT_PADDING; #endif } @@ -5273,12 +5648,11 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C { // NOTE: Considering icon height, probably different than text size GuiDrawIcon(iconId, (int)textBoundsPosition.x, (int)(textBounds.y + textBounds.height/2 - RAYGUI_ICON_SIZE*guiIconScale/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height)), guiIconScale, tint); - textBoundsPosition.x += (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); - textBoundsWidthOffset = (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); + textBoundsPosition.x += (float)(RAYGUI_ICON_SIZE*guiIconScale + RAYGUI_ICON_TEXT_PADDING); + textBoundsWidthOffset = (float)(RAYGUI_ICON_SIZE*guiIconScale + RAYGUI_ICON_TEXT_PADDING); } #endif - // Get size in bytes of text, - // considering end of line and line break + // Get size in bytes of text, considering end of line and line break int lineSize = 0; for (int c = 0; (lines[i][c] != '\0') && (lines[i][c] != '\n') && (lines[i][c] != '\r'); c++, lineSize++){ } float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize; @@ -5299,7 +5673,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C // NOTE: Normally, exiting the decoding sequence as soon as a bad byte is found (and return 0x3f) // but all of the bad bytes need to be drawn using the '?' symbol, moving one byte - if (codepoint == 0x3f) codepointSize = 1; // TODO: Review not recognized codepoints size + if (codepoint == 0x3f) codepointSize = 1; // WARNING: Not recognized codepoints size // Get glyph width to check if it goes out of bounds if (guiFont.glyphs[index].advanceX == 0) glyphWidth = ((float)guiFont.recs[index].width*scaleFactor); @@ -5315,7 +5689,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C textOffsetX = 0.0f; textOffsetY += (GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); - if (tempWrapCharMode) // Wrap at char level when too long words + if (tempWrapCharMode) // Wrap at char level when too long words { wrapMode = TEXT_WRAP_WORD; tempWrapCharMode = false; @@ -5346,12 +5720,12 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C } } - if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint + if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint else { - // TODO: There are multiple types of spaces in Unicode, + // WARNING: There are multiple types of spaces in Unicode, // maybe it's a good idea to add support for more: http://jkorpela.fi/chars/spaces.html - if ((codepoint != ' ') && (codepoint != '\t')) // Do not draw codepoints with no glyph + if ((codepoint != ' ') && (codepoint != '\t')) // Do not draw codepoints with no glyph { if (wrapMode == TEXT_WRAP_NONE) { @@ -5393,7 +5767,8 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C } if (wrapMode == TEXT_WRAP_NONE) posOffsetY += (float)(GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); - else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) posOffsetY += (textOffsetY + (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); + else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) + posOffsetY += (textOffsetY + GuiGetStyle(DEFAULT, TEXT_SIZE)); //--------------------------------------------------------------------------------- } @@ -5430,7 +5805,8 @@ static void GuiTooltip(Rectangle controlRec) { if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiControlExclusiveMode) { - Vector2 textSize = MeasureTextEx(GuiGetFont(), guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + Vector2 textSize = MeasureTextEx(guiFont, guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); if ((controlRec.x + textSize.x + 16) > GetScreenWidth()) controlRec.x -= (textSize.x + 16 - controlRec.width); @@ -5452,9 +5828,264 @@ static void GuiTooltip(Rectangle controlRec) } } +// Scroll bar control (used by GuiScrollPanel()) +static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) +{ + GuiState state = guiState; + + // Is the scrollbar horizontal or vertical? + bool isVertical = (bounds.width > bounds.height)? false : true; + + // The size (width or height depending on scrollbar type) of the spinner buttons + const int spinnerSize = GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)? + (isVertical? (int)bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) : + (int)bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0; + + // Arrow buttons [<] [>] [∧] [∨] + Rectangle arrowUpLeft = { 0 }; + Rectangle arrowDownRight = { 0 }; + + // Actual area of the scrollbar excluding the arrow buttons + Rectangle scrollbar = { 0 }; + + // Slider bar that moves --[///]----- + Rectangle slider = { 0 }; + + // Normalize value + if (value > maxValue) value = maxValue; + if (value < minValue) value = minValue; + + int valueRange = maxValue - minValue; + if (valueRange <= 0) valueRange = 1; + + int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); + if (sliderSize < 1) sliderSize = 1; // Consider a minimum slider size of 1 pixel + + // Calculate rectangles for all of the components + arrowUpLeft = RAYGUI_CLITERAL(Rectangle){ + (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), + (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), + (float)spinnerSize, (float)spinnerSize }; + + if (isVertical) + { + arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + bounds.height - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; + scrollbar = RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), arrowUpLeft.y + arrowUpLeft.height, bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)), bounds.height - arrowUpLeft.height - arrowDownRight.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) }; + + // Make sure the slider won't get outside of the scrollbar + sliderSize = (sliderSize >= scrollbar.height)? ((int)scrollbar.height - 2) : sliderSize; + slider = RAYGUI_CLITERAL(Rectangle){ + bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), + scrollbar.y + (int)(((float)(value - minValue)/valueRange)*(scrollbar.height - sliderSize)), + bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)), + (float)sliderSize }; + } + else // horizontal + { + arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; + scrollbar = RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x + arrowUpLeft.width, bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), bounds.width - arrowUpLeft.width - arrowDownRight.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)) }; + + // Make sure the slider won't get outside of the scrollbar + sliderSize = (sliderSize >= scrollbar.width)? ((int)scrollbar.width - 2) : sliderSize; + slider = RAYGUI_CLITERAL(Rectangle){ + scrollbar.x + (int)(((float)(value - minValue)/valueRange)*(scrollbar.width - sliderSize)), + bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), + (float)sliderSize, + bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)) }; + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (GUI_BUTTON_DOWN && + !CheckCollisionPointRec(mousePoint, arrowUpLeft) && + !CheckCollisionPointRec(mousePoint, arrowDownRight)) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + state = STATE_PRESSED; + + if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); + else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + + // Handle mouse wheel + float scrollDelta = GUI_SCROLL_DELTA; + if (scrollDelta != 0) value += (int)scrollDelta; + + // Handle mouse button down + if (GUI_BUTTON_PRESSED) + { + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + + // Check arrows click + if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + else if (!CheckCollisionPointRec(mousePoint, slider)) + { + // If click on scrollbar position but not on slider, place slider directly on that position + if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); + else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); + } + + state = STATE_PRESSED; + } + + // Keyboard control on mouse hover scrollbar + /* + if (isVertical) + { + if (GUI_KEY_DOWN(KEY_DOWN)) value += 5; + else if (GUI_KEY_DOWN(KEY_UP)) value -= 5; + } + else + { + if (GUI_KEY_DOWN(KEY_RIGHT)) value += 5; + else if (GUI_KEY_DOWN(KEY_LEFT)) value -= 5; + } + */ + } + + // Normalize value + if (value > maxValue) value = maxValue; + if (value < minValue) value = minValue; + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED))); // Draw the background + + GuiDrawRectangle(scrollbar, 0, BLANK, GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL))); // Draw the scrollbar active area background + GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BORDER + state*3))); // Draw the slider bar + + // Draw arrows (using icon if available) + if (GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)) + { +#if defined(RAYGUI_NO_ICONS) + GuiDrawText(isVertical? "^" : "<", + RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); + GuiDrawText(isVertical? "v" : ">", + RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); +#else + GuiDrawText(isVertical? GuiIconText(ICON_ARROW_UP_FILL, NULL) : GuiIconText(ICON_ARROW_LEFT_FILL, NULL), + RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_UP_FILL / ICON_ARROW_LEFT_FILL + GuiDrawText(isVertical? GuiIconText(ICON_ARROW_DOWN_FILL, NULL) : GuiIconText(ICON_ARROW_RIGHT_FILL, NULL), + RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_DOWN_FILL / ICON_ARROW_RIGHT_FILL +#endif + } + //-------------------------------------------------------------------- + + return value; +} + +// Update font image atlas to append raygui icons +static int GuiFontIconBaking(Image *imFont, Font font, Rectangle *whiteRec) +{ + int iconOffsetY = 0; + + // Check max glyph rec y bottom position in the atlas image, + // to start drawing icons below that line + int maxGlyphRecY = 0; + for (int i = 0; i < font.glyphCount; i++) + { + if ((font.recs[i].y + font.recs[i].height) > maxGlyphRecY) + maxGlyphRecY = (int)font.recs[i].y + (int)font.recs[i].height; + } + + int maxIconsPerLine = imFont->width/(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + int reqIconLines = RAYGUI_ICON_MAX_FONT_BACKED/maxIconsPerLine + RAYGUI_ICON_MAX_FONT_BACKED%maxIconsPerLine + 1; // One extra line + int reqHeight = reqIconLines*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + + // Check if image requires scaling and how much + if ((maxGlyphRecY + reqHeight) > imFont->height) + { + int newImHeight = 1; + while (newImHeight < (maxGlyphRecY + reqHeight)) newImHeight <<= 1; // Round to next POT + + char *newImData = (char *)RL_CALLOC(imFont->width*newImHeight*2, sizeof(char)); + memcpy(newImData, imFont->data, imFont->width*imFont->height*2); + RL_FREE(imFont->data); + + // Clear imFont bottom-right corner rec + for (int y = 0; y < 4; y++) + for (int x = 0; x < 4; x++) + ((unsigned short *)newImData)[(imFont->height - y - 1)*imFont->width + imFont->width - x - 1] = 0x0000; + + imFont->data = newImData; + imFont->height = newImHeight; + + // Set new image white corner and new white rec + for (int y = 0; y < 3; y++) + for (int x = 0; x < 3; x++) + ((unsigned short *)newImData)[(imFont->height - y - 1)*imFont->width + imFont->width - x - 1] = 0xffff; + + *whiteRec = RAYGUI_CLITERAL(Rectangle){ (float)imFont->width - 2, (float)imFont->height - 2, 1, 1 }; + } + + // Calculate image offset positions to start drawing + // NOTE: For Y, look for a multiple of icon size + 2*padding, for better alignment + int offsetX = RAYGUI_ICON_FONT_ATLAS_PADDING; + int offsetY = ((maxGlyphRecY + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING - 1))/ + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING))*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + + RAYGUI_ICON_FONT_ATLAS_PADDING; + + iconOffsetY = offsetY - RAYGUI_ICON_FONT_ATLAS_PADDING; + unsigned short *pixels = (unsigned short *)imFont->data; + + #define BIT_CHECK(a,b) ((a) & (1u<<(b))) + + for (int iconId = 0; iconId < RAYGUI_ICON_MAX_FONT_BACKED; iconId++) + { + // Wrap to next line if next icon won't fit + if ((offsetX + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING)) > imFont->width) + { + offsetX = RAYGUI_ICON_FONT_ATLAS_PADDING; + offsetY += RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING; + } + + for (int i = 0, y = 0; i < RAYGUI_ICON_DATA_ELEMENTS; i++) + { + unsigned int data = guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i]; + + for (int k = 0; k < 32; k++) + { + pixels[(offsetY + y)*imFont->width + offsetX + k%16] = (BIT_CHECK(data, k))? 0xffff : 0x00ff; + + if ((k == 15) || (k == 31)) y++; + } + } + + // Update current icon X position + offsetX += (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + } + + return iconOffsetY; +} + // Split controls text into multiple strings -// Also check for multiple columns (required by GuiToggleGroup()) -static char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow) +// NOTE: Re-used by GuiToggleSlider(), GuiComboBox(), GuiDropdownBox(), GuiListView(), GuiMessageBox(), GuiInputBox() +static char **GuiTextSplit(const char *text, char delimiter, int *count) { // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, @@ -5463,24 +6094,19 @@ static char **GuiTextSplit(const char *text, char delimiter, int *count, int *te // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE // NOTE: Those definitions could be externally provided if required - // TODO: HACK: GuiTextSplit() - Review how textRows are returned to user - // textRow is an externally provided array of integers that stores row number for every splitted string - #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS) #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128 #endif #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE) - #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 + #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 // WARNING: Max expected size for all concat items #endif - static char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL }; // String pointers array (points to buffer data) + static char *itemPtrs[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { 0 }; // String pointers array (points to buffer data) static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; // Buffer data (text input copy with '\0' added) memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE); - result[0] = buffer; - int counter = 1; - - if (textRow != NULL) textRow[0] = 0; + itemPtrs[0] = buffer; + int itemCounter = 1; // Count how many substrings text contains and point to every one of them for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++) @@ -5489,24 +6115,16 @@ static char **GuiTextSplit(const char *text, char delimiter, int *count, int *te if (buffer[i] == '\0') break; else if ((buffer[i] == delimiter) || (buffer[i] == '\n')) { - result[counter] = buffer + i + 1; + itemPtrs[itemCounter] = buffer + i + 1; + buffer[i] = '\0'; // Set terminator for current item - if (textRow != NULL) - { - if (buffer[i] == '\n') textRow[counter] = textRow[counter - 1] + 1; - else textRow[counter] = textRow[counter - 1]; - } - - buffer[i] = '\0'; // Set an end of string at this point - - counter++; - if (counter >= RAYGUI_TEXTSPLIT_MAX_ITEMS) break; + itemCounter++; + if (itemCounter >= RAYGUI_TEXTSPLIT_MAX_ITEMS) break; } } - *count = counter; - - return result; + *count = itemCounter; + return itemPtrs; } // Convert color data from RGB to HSV @@ -5633,179 +6251,9 @@ static Vector3 ConvertHSVtoRGB(Vector3 hsv) return rgb; } -// Scroll bar control (used by GuiScrollPanel()) -static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) -{ - GuiState state = guiState; - - // Is the scrollbar horizontal or vertical? - bool isVertical = (bounds.width > bounds.height)? false : true; - - // The size (width or height depending on scrollbar type) of the spinner buttons - const int spinnerSize = GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)? - (isVertical? (int)bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) : - (int)bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0; - - // Arrow buttons [<] [>] [∧] [∨] - Rectangle arrowUpLeft = { 0 }; - Rectangle arrowDownRight = { 0 }; - - // Actual area of the scrollbar excluding the arrow buttons - Rectangle scrollbar = { 0 }; - - // Slider bar that moves --[///]----- - Rectangle slider = { 0 }; - - // Normalize value - if (value > maxValue) value = maxValue; - if (value < minValue) value = minValue; - - int valueRange = maxValue - minValue; - if (valueRange <= 0) valueRange = 1; - - int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); - if (sliderSize < 1) sliderSize = 1; // TODO: Consider a minimum slider size - - // Calculate rectangles for all of the components - arrowUpLeft = RAYGUI_CLITERAL(Rectangle){ - (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), - (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), - (float)spinnerSize, (float)spinnerSize }; - - if (isVertical) - { - arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + bounds.height - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; - scrollbar = RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), arrowUpLeft.y + arrowUpLeft.height, bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)), bounds.height - arrowUpLeft.height - arrowDownRight.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) }; - - // Make sure the slider won't get outside of the scrollbar - sliderSize = (sliderSize >= scrollbar.height)? ((int)scrollbar.height - 2) : sliderSize; - slider = RAYGUI_CLITERAL(Rectangle){ - bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), - scrollbar.y + (int)(((float)(value - minValue)/valueRange)*(scrollbar.height - sliderSize)), - bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)), - (float)sliderSize }; - } - else // horizontal - { - arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; - scrollbar = RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x + arrowUpLeft.width, bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), bounds.width - arrowUpLeft.width - arrowDownRight.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)) }; - - // Make sure the slider won't get outside of the scrollbar - sliderSize = (sliderSize >= scrollbar.width)? ((int)scrollbar.width - 2) : sliderSize; - slider = RAYGUI_CLITERAL(Rectangle){ - scrollbar.x + (int)(((float)(value - minValue)/valueRange)*(scrollbar.width - sliderSize)), - bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), - (float)sliderSize, - bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)) }; - } - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GUI_POINTER_POSITION; - - if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds - { - if (GUI_BUTTON_DOWN && - !CheckCollisionPointRec(mousePoint, arrowUpLeft) && - !CheckCollisionPointRec(mousePoint, arrowDownRight)) - { - if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) - { - state = STATE_PRESSED; - - if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); - else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); - } - } - else - { - guiControlExclusiveMode = false; - guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; - } - } - else if (CheckCollisionPointRec(mousePoint, bounds)) - { - state = STATE_FOCUSED; - - // Handle mouse wheel - float scrollDelta = GUI_SCROLL_DELTA; - if (scrollDelta != 0) value += (int)scrollDelta; - - // Handle mouse button down - if (GUI_BUTTON_PRESSED) - { - guiControlExclusiveMode = true; - guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts - - // Check arrows click - if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - else if (!CheckCollisionPointRec(mousePoint, slider)) - { - // If click on scrollbar position but not on slider, place slider directly on that position - if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); - else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); - } - - state = STATE_PRESSED; - } - - // Keyboard control on mouse hover scrollbar - /* - if (isVertical) - { - if (GUI_KEY_DOWN(KEY_DOWN)) value += 5; - else if (GUI_KEY_DOWN(KEY_UP)) value -= 5; - } - else - { - if (GUI_KEY_DOWN(KEY_RIGHT)) value += 5; - else if (GUI_KEY_DOWN(KEY_LEFT)) value -= 5; - } - */ - } - - // Normalize value - if (value > maxValue) value = maxValue; - if (value < minValue) value = minValue; - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED))); // Draw the background - - GuiDrawRectangle(scrollbar, 0, BLANK, GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL))); // Draw the scrollbar active area background - GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BORDER + state*3))); // Draw the slider bar - - // Draw arrows (using icon if available) - if (GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)) - { -#if defined(RAYGUI_NO_ICONS) - GuiDrawText(isVertical? "^" : "<", - RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); - GuiDrawText(isVertical? "v" : ">", - RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); -#else - GuiDrawText(isVertical? "#121#" : "#118#", - RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_UP_FILL / ICON_ARROW_LEFT_FILL - GuiDrawText(isVertical? "#120#" : "#119#", - RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_DOWN_FILL / ICON_ARROW_RIGHT_FILL -#endif - } - //-------------------------------------------------------------------- - - return value; -} - // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f -// WARNING: It multiplies current alpha by alpha scale factor +// WARNING: It multiplies current alpha by alpha scale factor, +// raylib Fade() multiplies alpha by 255.0f static Color GuiFade(Color color, float alpha) { if (alpha < 0.0f) alpha = 0.0f; @@ -5830,6 +6278,19 @@ static Color GetColor(int hexValue) return color; } +// Get color with alpha applied, alpha goes from 0.0f to 1.0f +static Color Fade(Color color, float alpha) +{ + Color result = color; + + if (alpha < 0.0f) alpha = 0.0f; + else if (alpha > 1.0f) alpha = 1.0f; + + result.a = (unsigned char)(255.0f*alpha); + + return result; +} + // Returns hexadecimal value for a Color static int ColorToInt(Color color) { @@ -5854,7 +6315,8 @@ static const char *TextFormat(const char *text, ...) #define RAYGUI_TEXTFORMAT_MAX_SIZE 256 #endif - static char buffer[RAYGUI_TEXTFORMAT_MAX_SIZE]; + static char buffer[RAYGUI_TEXTFORMAT_MAX_SIZE] = { 0 }; + memset(buffer, 0, RAYGUI_TEXTFORMAT_MAX_SIZE); va_list args; va_start(args, text); @@ -5864,61 +6326,6 @@ static const char *TextFormat(const char *text, ...) return buffer; } -// Draw rectangle with vertical gradient fill color -// NOTE: This function is only used by GuiColorPicker() -static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2) -{ - Rectangle bounds = { (float)posX, (float)posY, (float)width, (float)height }; - DrawRectangleGradientEx(bounds, color1, color2, color2, color1); -} - -// Split string into multiple strings -char **TextSplit(const char *text, char delimiter, int *count) -{ - // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) - // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, - // all used memory is static... it has some limitations: - // 1. Maximum number of possible split strings is set by RAYGUI_TEXTSPLIT_MAX_ITEMS - // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE - - #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS) - #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128 - #endif - #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE) - #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 - #endif - - static const char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL }; - static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; - memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE); - - result[0] = buffer; - int counter = 0; - - if (text != NULL) - { - counter = 1; - - // Count how many substrings text contains and point to every one of them - for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++) - { - buffer[i] = text[i]; - if (buffer[i] == '\0') break; - else if (buffer[i] == delimiter) - { - buffer[i] = '\0'; // Set an end of string at this point - result[counter] = buffer + i + 1; - counter++; - - if (counter == RAYGUI_TEXTSPLIT_MAX_ITEMS) break; - } - } - } - - *count = counter; - return result; -} - // Get integer value from text // NOTE: This function replaces atoi() [stdlib.h] static int TextToInteger(const char *text) diff --git a/examples/shaders/raygui.h b/examples/shaders/raygui.h index 03e487912..f7a116150 100644 --- a/examples/shaders/raygui.h +++ b/examples/shaders/raygui.h @@ -1,6 +1,6 @@ /******************************************************************************************* * -* raygui v5.0-dev - A simple and easy-to-use immediate-mode gui library +* raygui v5.0 - A simple and easy-to-use immediate-mode gui library * * DESCRIPTION: * raygui is a tools-dev-focused immediate-mode-gui library based on raylib but also @@ -37,7 +37,7 @@ * - Line * - Panel --> StatusBar * - ScrollPanel --> StatusBar -* - TabBar --> Button +* - TabBar --> Toggle, Button * * # Basic Controls * - Label @@ -134,6 +134,10 @@ * Includes custom ricons.h header defining a set of custom icons, * this file can be generated using rGuiIcons tool * +* #define RAYGUI_FONT_ICONS_BAKING +* On gui font loading from style file, append the icons to font atlas image, so, +* icons can be drawn along the text as a texture, instead of using shapes to draw them +* * #define RAYGUI_DEBUG_RECS_BOUNDS * Draw control bounds rectangles for debug * @@ -141,16 +145,26 @@ * Draw text bounds rectangles for debug * * VERSIONS HISTORY: -* 5.0 (xx-Mar-2026) ADDED: Support up to 32 controls (v500) +* 5.0 (20-Jul-2026) ADDED: NEW control: GuiTabBar() +* ADDED: Support up to 512 icons (v500) +* ADDED: Support icons baking into font atlas image * ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes -* ADDED: GuiValueBoxFloat() +* ADDED: GuiValueBoxFloat(), with floats support * ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP * ADDED: GuiListView() property: LIST_ITEMS_BORDER_WIDTH -* ADDED: GuiLoadIconsFromMemory() -* ADDED: Multiple new icons +* ADDED: GuiLoadIconsFromMemory(), used by GuiLoadIcons() * ADDED: Macros for inputs customization, raylib decoupling +* ADDED: Control result return values: 1-RESULT_PRESSED, 2-RESULT_CHANGED, >2-Control_custom * REMOVED: GuiSpinner() from controls list, using BUTTON + VALUEBOX properties * REMOVED: GuiSliderPro(), functionality was redundant +* REMOVED: TextSplit() raylib function requirement on RAYGUI_STANDALONE +* REDESIGNED: WARNING: GuiLoadStyleFromMemory() to support icons baking into font atlas +* REDESIGNED: GuiToggleGroup() to process rows/cols with no need for GuiTextSplit() +* REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion +* REDESIGNED: WARNING: TEXT_LINE_SPACING does not consider text height, only lines spacing +* REDESIGNED: WARNING: GuiMessageBox(), added parameter for btn return, unify result +* REDESIGNED: WARNING: GuiTextInputBox(), added parameter for btn return, unify result +* REVIEWED: GuiLoadIconsFromMemory(), fixed memory issues * REVIEWED: Controls using text labels to use LABEL properties * REVIEWED: Replaced sprintf() by snprintf() for more safety * REVIEWED: GuiTabBar(), close tab with mouse middle button @@ -165,8 +179,6 @@ * REVIEWED: GuiProgressBar(), improved borders computing * REVIEWED: GuiTextBox(), multiple improvements: autocursor and more * REVIEWED: Functions descriptions, removed wrong return value reference -* REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion -* REDESIGNED: WARNING: TEXT_LINE_SPACING does not consider text height, only lines spacing * * 4.0 (12-Sep-2023) ADDED: GuiToggleSlider() * ADDED: GuiColorPickerHSV() and GuiColorPanelHSV() @@ -273,7 +285,7 @@ * 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria * * DEPENDENCIES: -* raylib 5.6-dev - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing +* raylib 6.1-dev - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing * * STANDALONE MODE: * By default raygui depends on raylib mostly for the inputs and the drawing functionality but that dependency can be disabled @@ -340,10 +352,10 @@ #ifndef RAYGUI_H #define RAYGUI_H -#define RAYGUI_VERSION_MAJOR 4 -#define RAYGUI_VERSION_MINOR 5 +#define RAYGUI_VERSION_MAJOR 5 +#define RAYGUI_VERSION_MINOR 0 #define RAYGUI_VERSION_PATCH 0 -#define RAYGUI_VERSION "5.0-dev" +#define RAYGUI_VERSION "5.0" #if !defined(RAYGUI_STANDALONE) #include "raylib.h" @@ -357,7 +369,13 @@ #elif defined(USE_LIBTYPE_SHARED) #define RAYGUIAPI __declspec(dllimport) // Using the library as a Win32 shared library (.dll) #endif - #define _CRT_SECURE_NO_WARNINGS // Disable unsafe warnings on scanf() functions in MSVC + #if !defined(_CRT_SECURE_NO_WARNINGS) + #define _CRT_SECURE_NO_WARNINGS // Disable unsafe warnings on scanf() functions in MSVC + #endif +#else + #if defined(BUILD_LIBTYPE_SHARED) + #define RAYGUIAPI __attribute__((visibility("default"))) // Building as a Unix shared library (.so/.dylib) + #endif #endif // Function specifiers definition @@ -377,8 +395,8 @@ #define RAYGUI_LOG(...) #endif +#if !defined(RAYGUI_STANDALONE) // Macros to define required UI inputs, including mapping to gamepad controls -// TODO: Define additionally required macros for missing inputs #if !defined(GUI_BUTTON_DOWN) #define GUI_BUTTON_DOWN (IsMouseButtonDown(MOUSE_LEFT_BUTTON) || IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) #endif @@ -389,13 +407,15 @@ #if !defined(GUI_BUTTON_PRESSED) #define GUI_BUTTON_PRESSED (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsGamepadButtonPressed(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) #endif -// TODO: WARNING: GuiTabBar() still requires IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON) +#if !defined(GUI_BUTTON_PRESSED_MID) + #define GUI_BUTTON_PRESSED_MID (IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON) || IsGamepadButtonPressed(0, GAMEPAD_BUTTON_RIGHT_FACE_UP)) +#endif #if !defined(GUI_BUTTON_RELEASED) #define GUI_BUTTON_RELEASED (IsMouseButtonReleased(MOUSE_LEFT_BUTTON) || IsGamepadButtonReleased(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) #endif #if !defined(GUI_SCROLL_DELTA) // Mapping to scroll delta changes - // TODO: Review inconsistencies between platforms + // TODO: Review mouse scroll inconsistencies between platforms #if defined(PLATFORM_WEB) // NOTE: Gamepad axis triggers not detected on web platform #define GUI_SCROLL_DELTA ((float)IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_TRIGGER_2) - (float)IsGamepadButtonDown(0, GAMEPAD_BUTTON_LEFT_TRIGGER_2)) @@ -415,6 +435,18 @@ #if !defined(GUI_INPUT_KEY) #define GUI_INPUT_KEY GetCharPressed() #endif +#else + #define GUI_BUTTON_DOWN 0 + #define GUI_BUTTON_DOWN_ALT 0 + #define GUI_BUTTON_PRESSED 0 + #define GUI_BUTTON_PRESSED_MID 0 + #define GUI_BUTTON_RELEASED 0 + #define GUI_SCROLL_DELTA 0 + #define GUI_POINTER_POSITION (Vector2){ 0 } + #define GUI_KEY_DOWN(key) 0 + #define GUI_KEY_PRESSED(key) 0 + #define GUI_INPUT_KEY 0 +#endif //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -449,6 +481,8 @@ unsigned char a; } Color; +#define BLANK (Color){ 0, 0, 0, 0 } // Blank (Transparent) + // Rectangle type typedef struct Rectangle { float x; @@ -457,7 +491,7 @@ float height; } Rectangle; - // TODO: Texture2D type is very coupled to raylib, required by Font type + // NOTE: Texture2D type is very coupled to raylib, required by Font type // It should be redesigned to be provided by user typedef struct Texture { unsigned int id; // OpenGL texture id @@ -488,7 +522,7 @@ Image image; // Character image data } GlyphInfo; - // TODO: Font type is very coupled to raylib, mostly required by GuiLoadStyle() + // NOTE: Font type is very coupled to raylib, mostly required by GuiLoadStyle() // It should be redesigned to be provided by user typedef struct Font { int baseSize; // Base size (default chars height) @@ -521,6 +555,15 @@ typedef struct GuiTextStyle { } GuiTextStyle; */ +// Gui control result +typedef enum { + RESULT_NONE = 0, + RESULT_PRESSED = 1, + RESULT_CHANGED = 2, + + RESULT_TAB_CLOSE = 4 // GuiTabBar(), tab close request +} GuiResult; + // Gui control state typedef enum { STATE_NORMAL = 0, @@ -553,88 +596,95 @@ typedef enum { } GuiTextWrapMode; // Gui controls +// NOTE: Up to 16 controls supported or 32 controls (v500) typedef enum { // Default -> populates to all controls when set - DEFAULT = 0, + DEFAULT = 0, // Basic controls - LABEL, // Used also for: LABELBUTTON - BUTTON, - TOGGLE, // Used also for: TOGGLEGROUP - SLIDER, // Used also for: SLIDERBAR, TOGGLESLIDER - PROGRESSBAR, - CHECKBOX, - COMBOBOX, - DROPDOWNBOX, - TEXTBOX, // Used also for: TEXTBOXMULTI - VALUEBOX, - CONTROL11, - LISTVIEW, - COLORPICKER, - SCROLLBAR, - STATUSBAR + LABEL = 1, // Used also for: LABELBUTTON + BUTTON = 2, + TOGGLE = 3, // Used also for: TOGGLEGROUP + SLIDER = 4, // Used also for: SLIDERBAR, TOGGLESLIDER + PROGRESSBAR = 5, + CHECKBOX = 6, + COMBOBOX = 7, + DROPDOWNBOX = 8, + TEXTBOX = 9, // Used also for: TEXTBOXMULTI + VALUEBOX = 10, + TABBAR = 11, + LISTVIEW = 12, + COLORPICKER = 13, + SCROLLBAR = 14, + STATUSBAR = 15 + // NOTE: More controls can be added if required } GuiControl; -// Gui base properties for every control -// NOTE: RAYGUI_MAX_PROPS_BASE properties (by default 16 properties) +// Controls BASE properties for every control (RAYGUI_MAX_PROPS_BASE = 16) +// NOTE: Properties required for all controls, DEFAULT control sets +// default values for them but they can be overriden per control typedef enum { - BORDER_COLOR_NORMAL = 0, // Control border color in STATE_NORMAL - BASE_COLOR_NORMAL, // Control base color in STATE_NORMAL - TEXT_COLOR_NORMAL, // Control text color in STATE_NORMAL - BORDER_COLOR_FOCUSED, // Control border color in STATE_FOCUSED - BASE_COLOR_FOCUSED, // Control base color in STATE_FOCUSED - TEXT_COLOR_FOCUSED, // Control text color in STATE_FOCUSED - BORDER_COLOR_PRESSED, // Control border color in STATE_PRESSED - BASE_COLOR_PRESSED, // Control base color in STATE_PRESSED - TEXT_COLOR_PRESSED, // Control text color in STATE_PRESSED - BORDER_COLOR_DISABLED, // Control border color in STATE_DISABLED - BASE_COLOR_DISABLED, // Control base color in STATE_DISABLED - TEXT_COLOR_DISABLED, // Control text color in STATE_DISABLED - BORDER_WIDTH = 12, // Control border size, 0 for no border - //TEXT_SIZE, // Control text size (glyphs max height) -> GLOBAL for all controls - //TEXT_SPACING, // Control text spacing between glyphs -> GLOBAL for all controls - //TEXT_LINE_SPACING, // Control text spacing between lines -> GLOBAL for all controls - TEXT_PADDING = 13, // Control text padding, not considering border - TEXT_ALIGNMENT = 14, // Control text horizontal alignment inside control text bound (after border and padding) - //TEXT_WRAP_MODE // Control text wrap-mode inside text bounds -> GLOBAL for all controls + BORDER_COLOR_NORMAL = 0, // Control border color in STATE_NORMAL + BASE_COLOR_NORMAL = 1, // Control base color in STATE_NORMAL + TEXT_COLOR_NORMAL = 2, // Control text color in STATE_NORMAL + BORDER_COLOR_FOCUSED = 3, // Control border color in STATE_FOCUSED + BASE_COLOR_FOCUSED = 4, // Control base color in STATE_FOCUSED + TEXT_COLOR_FOCUSED = 5, // Control text color in STATE_FOCUSED + BORDER_COLOR_PRESSED = 6, // Control border color in STATE_PRESSED + BASE_COLOR_PRESSED = 7, // Control base color in STATE_PRESSED + TEXT_COLOR_PRESSED = 8, // Control text color in STATE_PRESSED + BORDER_COLOR_DISABLED = 9, // Control border color in STATE_DISABLED + BASE_COLOR_DISABLED = 10, // Control base color in STATE_DISABLED + TEXT_COLOR_DISABLED = 11, // Control text color in STATE_DISABLED + BORDER_WIDTH = 12, // Control border size, 0 for no border + TEXT_PADDING = 13, // Control text padding, not considering border + TEXT_ALIGNMENT = 14, // Control text horizontal alignment inside control text bound (after border and padding): 0-Left, 1-Center, 2-Right + BASEPROP16 = 15 // Not used yet... } GuiControlProperty; -// TODO: Which text styling properties should be global or per-control? -// At this moment TEXT_PADDING and TEXT_ALIGNMENT is configured and saved per control while -// TEXT_SIZE, TEXT_SPACING, TEXT_LINE_SPACING, TEXT_ALIGNMENT_VERTICAL, TEXT_WRAP_MODE are global and -// should be configured by user as needed while defining the UI layout -// Gui extended properties depend on control -// NOTE: RAYGUI_MAX_PROPS_EXTENDED properties (by default, max 8 properties) +// WARNING: Some properties have been chosen to be global with DEFAULT - EXTENDED properties: +// - TEXT_SIZE, // Control text size (glyphs max height) +// - TEXT_SPACING, // Control text spacing between glyphs +// - TEXT_LINE_SPACING, // Control text spacing between lines +// - TEXT_WRAP_MODE // Control text wrap-mode inside text bounds +// +// While other properties can be setup per globally (DEFAULT) or per control: +// - TEXT_PADDING // Control text padding, not considering border +// - TEXT_ALIGNMENT // Control text horizontal alignment inside control text bound + + +// Controls EXTENDED properties (RAYGUI_MAX_PROPS_EXTENDED = 8) +// WARNING: Only 8 slots vailable for those properties per control, including DEFAULT //---------------------------------------------------------------------------------- -// DEFAULT extended properties -// NOTE: Those properties are common to all controls or global -// WARNING: Only 8 slots vailable for those properties by default +// DEFAULT control, extended properties +// NOTE: Those properties are global for all controls, they can not be setup per control typedef enum { - TEXT_SIZE = 16, // Text size (glyphs max height) - TEXT_SPACING, // Text spacing between glyphs - LINE_COLOR, // Line control color - BACKGROUND_COLOR, // Background color - TEXT_LINE_SPACING, // Text spacing between lines - TEXT_ALIGNMENT_VERTICAL, // Text vertical alignment inside text bounds (after border and padding) - TEXT_WRAP_MODE // Text wrap-mode inside text bounds - //TEXT_DECORATION // Text decoration: 0-None, 1-Underline, 2-Line-through, 3-Overline - //TEXT_DECORATION_THICK // Text decoration line thickness + TEXT_SIZE = 16, // Text size (glyphs max height) + TEXT_SPACING = 17, // Text spacing between glyphs + LINE_COLOR = 18, // Line control color + BACKGROUND_COLOR = 19, // Background color + TEXT_LINE_SPACING = 20, // Text spacing between lines + TEXT_ALIGNMENT_VERTICAL = 21, // Text vertical alignment inside text bounds (after border and padding): 0-Top, 1-Middle, 2-Bottom + TEXT_WRAP_MODE = 22, // Text wrap-mode inside text bounds + EXTPROP08 = 23 // Not used yet... } GuiDefaultProperty; -// Other possible text properties: -// TEXT_WEIGHT // Normal, Italic, Bold -> Requires specific font change -// TEXT_INDENT // Text indentation -> Now using TEXT_PADDING... +// Other possible text extended properties: +// TEXT_DECORATION // Text decoration: 0-None, 1-Underline, 2-Line-through, 3-Overline +// TEXT_DECORATION_THICK // Text decoration line thickness +// TEXT_FONT_WEIGHT // Text font weight: 0-Normal, 1-Bold, 2-Italic -> Requires specific font change // Label //typedef enum { } GuiLabelProperty; -// Button/Spinner +// Button //typedef enum { } GuiButtonProperty; // Toggle/ToggleGroup typedef enum { GROUP_PADDING = 16, // ToggleGroup separation between toggles + GROUP_WIDTH_FULL // ToggleGroup bounds width considers all items: 0-Width per item, 1-Full width } GuiToggleProperty; // Slider/SliderBar @@ -646,7 +696,7 @@ typedef enum { // ProgressBar typedef enum { PROGRESS_PADDING = 16, // ProgressBar internal padding - PROGRESS_SIDE, // ProgressBar increment side: 0-left->right, 1-right-left + PROGRESS_SIDE, // ProgressBar increment side: 0-Left->Right, 1-Right->Left } GuiProgressBarProperty; // ScrollBar @@ -675,12 +725,12 @@ typedef enum { ARROW_PADDING = 16, // DropdownBox arrow separation from border and items DROPDOWN_ITEMS_SPACING, // DropdownBox items separation DROPDOWN_ARROW_HIDDEN, // DropdownBox arrow hidden - DROPDOWN_ROLL_UP // DropdownBox roll up flag (default rolls down) + DROPDOWN_ROLL_UP // DropdownBox roll up flag: 0-Roll down, 1-Roll up } GuiDropdownBoxProperty; // TextBox/TextBoxMulti/ValueBox/Spinner typedef enum { - TEXT_READONLY = 16, // TextBox in read-only mode: 0-text editable, 1-text no-editable + TEXT_READONLY = 16, // TextBox in read-only mode: 0-Text editable, 1-Text read-only } GuiTextBoxProperty; // ValueBox/Spinner @@ -689,31 +739,35 @@ typedef enum { SPINNER_BUTTON_SPACING, // Spinner buttons separation } GuiValueBoxProperty; -// Control11 -//typedef enum { } GuiControl11Property; +// TabBar +typedef enum { + TAB_ITEMS_WIDTH = 16, // TabBar tab items width + TAB_CLOSE_BUTTON, // TabBar tab close button: 0-Not shown, 1-Shown + TAB_LINE_SIDE, // TabBar tabs side: 0-Bottom, 1-Top +} GuiTabBarProperty; // ListView +#define SCROLLBAR_LEFT_SIDE 0 +#define SCROLLBAR_RIGHT_SIDE 1 + typedef enum { LIST_ITEMS_HEIGHT = 16, // ListView items height LIST_ITEMS_SPACING, // ListView items separation SCROLLBAR_WIDTH, // ListView scrollbar size (usually width) - SCROLLBAR_SIDE, // ListView scrollbar side (0-SCROLLBAR_LEFT_SIDE, 1-SCROLLBAR_RIGHT_SIDE) + SCROLLBAR_SIDE, // ListView scrollbar side: 0-Left side, 1-Right Side LIST_ITEMS_BORDER_NORMAL, // ListView items border enabled in normal state LIST_ITEMS_BORDER_WIDTH // ListView items border width } GuiListViewProperty; // ColorPicker typedef enum { - COLOR_SELECTOR_SIZE = 16, + COLOR_SELECTOR_SIZE = 16, // ColorPicker selector square size HUEBAR_WIDTH, // ColorPicker right hue bar width HUEBAR_PADDING, // ColorPicker right hue bar separation from panel HUEBAR_SELECTOR_HEIGHT, // ColorPicker right hue bar selector height HUEBAR_SELECTOR_OVERFLOW // ColorPicker right hue bar selector overflow } GuiColorPickerProperty; -#define SCROLLBAR_LEFT_SIDE 0 -#define SCROLLBAR_RIGHT_SIDE 1 - //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- @@ -747,6 +801,7 @@ RAYGUIAPI int GuiGetStyle(int control, int property); // Get one style // Styles loading functions RAYGUIAPI void GuiLoadStyle(const char *fileName); // Load style file over global style variable (.rgs) +RAYGUIAPI void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only) RAYGUIAPI void GuiLoadStyleDefault(void); // Load style default over global style // Tooltips management functions @@ -760,6 +815,7 @@ RAYGUIAPI const char *GuiIconText(int iconId, const char *text); // Get text wit RAYGUIAPI void GuiSetIconScale(int scale); // Set default icon drawing size RAYGUIAPI unsigned int *GuiGetIcons(void); // Get raygui icons data pointer RAYGUIAPI char **GuiLoadIcons(const char *fileName, bool loadIconsName); // Load raygui icons file (.rgi) into internal icons data +RAYGUIAPI char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName); // Load raygui icons file (.rgi) from memory into internal icons data RAYGUIAPI void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color); // Draw icon using pixel size at specified position #endif @@ -773,7 +829,6 @@ RAYGUIAPI int GuiWindowBox(Rectangle bounds, const char *title); RAYGUIAPI int GuiGroupBox(Rectangle bounds, const char *text); // Group Box control with text name RAYGUIAPI int GuiLine(Rectangle bounds, const char *text); // Line separator control, could contain text RAYGUIAPI int GuiPanel(Rectangle bounds, const char *text); // Panel control, useful to group controls -RAYGUIAPI int GuiTabBar(Rectangle bounds, char **text, int count, int *active); // Tab Bar control, returns TAB to be closed or -1 RAYGUIAPI int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view); // Scroll Panel control // Basic controls set @@ -801,15 +856,17 @@ RAYGUIAPI int GuiGrid(Rectangle bounds, const char *text, float spacing, int sub // Advance controls set RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active); // List View control -RAYGUIAPI int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus); // List View with extended parameters -RAYGUIAPI int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons); // Message Box control, displays a message -RAYGUIAPI int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive); // Text Input Box control, ask for text, supports secret -RAYGUIAPI int GuiColorPicker(Rectangle bounds, const char *text, Color *color); // Color Picker control (multiple color controls) +RAYGUIAPI int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus); // List View control, using text entries list and returning focus entry +RAYGUIAPI int GuiTabBar(Rectangle bounds, const char *text, int *hscroll, int *active); // Tab Bar control +RAYGUIAPI int GuiTabBarEx(Rectangle bounds, char **text, int count, int *hscroll, int *active, int *focus); // Tab Bar control, using text entries list and returning focus entry +RAYGUIAPI int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *btnText, int *btnActive); // Message Box control, displays a message +RAYGUIAPI int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, char *text, int textSize, const char *btnText, int *btnActive, bool *secretViewActive); // Text Input Box control, ask for text, supports secret +RAYGUIAPI int GuiColorPicker(Rectangle bounds, const char *text, Color *color); // Color Picker control, includes Color bar controls RAYGUIAPI int GuiColorPanel(Rectangle bounds, const char *text, Color *color); // Color Panel control RAYGUIAPI int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha); // Color Bar Alpha control RAYGUIAPI int GuiColorBarHue(Rectangle bounds, const char *text, float *value); // Color Bar Hue control -RAYGUIAPI int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Picker control that avoids conversion to RGB on each call (multiple color controls) -RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control that updates Hue-Saturation-Value color value, used by GuiColorPickerHSV() +RAYGUIAPI int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Picker control, using Hue-Saturation-Value color data, includes Color bar controls +RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control, using Hue-Saturation-Value color data //---------------------------------------------------------------------------------------------------------- #if !defined(RAYGUI_NO_ICONS) @@ -1069,16 +1126,17 @@ typedef enum { ICON_CONE = 247, ICON_ELLIPSOID = 248, ICON_CAPSULE = 249, - ICON_250 = 250, - ICON_251 = 251, - ICON_252 = 252, - ICON_253 = 253, - ICON_254 = 254, - ICON_255 = 255 + ICON_FILETYPE_FONT = 250, + ICON_FILETYPE_3D = 251, + ICON_FILETYPE_CODE_XML = 252, + ICON_FILETYPE_CODE_C = 253, + ICON_FILETYPE_CODE_PYTHON = 254, + ICON_FILETYPE_CODE_JS = 255, + ICON_FILETYPE_ICON = 256, } GuiIconName; #endif -#endif +#endif // RAYGUI_NO_ICONS #if defined(__cplusplus) } // Prevents name mangling of functions @@ -1094,11 +1152,11 @@ typedef enum { #if defined(RAYGUI_IMPLEMENTATION) -#include // required for: isspace() [GuiTextBox()] #include // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()] #include // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy() #include // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()] #include // Required for: roundf() [GuiColorPicker()] +#include // Required for: isspace() [GuiTextBox()] // Allow custom memory allocators #if defined(RAYGUI_MALLOC) || defined(RAYGUI_CALLOC) || defined(RAYGUI_FREE) @@ -1127,9 +1185,11 @@ typedef enum { #if !defined(RAYGUI_NO_ICONS) && !defined(RAYGUI_CUSTOM_ICONS) // Embedded icons, no external file provided -#define RAYGUI_ICON_SIZE 16 // Size of icons in pixels (squared) -#define RAYGUI_ICON_MAX_ICONS 256 // Maximum number of icons -#define RAYGUI_ICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id +#define RAYGUI_ICON_SIZE 16 // Size of icons in pixels (squared) +#define RAYGUI_ICON_MAX_ICONS 512 // Maximum number of icons +#define RAYGUI_ICON_MAX_FONT_BACKED 257 // Maximum number of icons to back in font atlas +#define RAYGUI_ICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id +#define RAYGUI_ICON_FONT_ATLAS_PADDING 1 // Padding between backed icons in font atlas // Icons data is defined by bit array (every bit represents one pixel) // Those arrays are stored as unsigned int data arrays, so, @@ -1147,7 +1207,7 @@ typedef enum { // NOTE 2: A different icon set could be loaded over this array using GuiLoadIcons(), // but loaded icons set must be same RAYGUI_ICON_SIZE and no more than RAYGUI_ICON_MAX_ICONS // -// guiIcons size is by default: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 KB +// guiIcons size is by default: 512*(16*16/32) = 16384 bytes = 16 KB //---------------------------------------------------------------------------------- static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_NONE @@ -1400,18 +1460,20 @@ static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = 0x00800000, 0x01400140, 0x02200220, 0x04100410, 0x08080808, 0x1c1c13e4, 0x08081004, 0x000007f0, // ICON_CONE 0x00000000, 0x07e00000, 0x20841918, 0x40824082, 0x40824082, 0x19182084, 0x000007e0, 0x00000000, // ICON_ELLIPSOID 0x00000000, 0x00000000, 0x20041ff8, 0x40024002, 0x40024002, 0x1ff82004, 0x00000000, 0x00000000, // ICON_CAPSULE - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_250 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_251 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_252 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_253 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_254 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_255 + 0x3ff00000, 0x201c2010, 0x21042004, 0x22842384, 0x264426c4, 0x2c242fe4, 0x20043e74, 0x00003ffc, // ICON_FILETYPE_FONT + 0x3ff00000, 0x201c2010, 0x20042004, 0x27742004, 0x29742944, 0x27742944, 0x20042004, 0x00003ffc, // ICON_FILETYPE_3D + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x24242244, 0x24242814, 0x20042244, 0x00003ffc, // ICON_FILETYPE_XML + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x21042f04, 0x21042104, 0x20042f04, 0x00003ffc, // ICON_FILETYPE_C + 0x3ff00000, 0x201c2010, 0x23842004, 0x2bf42a04, 0x2fd42814, 0x21c42054, 0x20042004, 0x00003ffc, // ICON_FILETYPE_PYTHON + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x22842ee4, 0x28a42e84, 0x20042e64, 0x00003ffc, // ICON_FILETYPE_JS + 0x3ff00000, 0x241c2010, 0x2a8c3104, 0x28242454, 0x2ed42004, 0x2a542a54, 0x20042ed4, 0x00003ffc, // ICON_FILETYPE_ICON + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_257 }; // NOTE: A pointer to current icons array should be defined static unsigned int *guiIconsPtr = guiIcons; -#endif // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS +#endif // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS #ifndef RAYGUI_ICON_SIZE #define RAYGUI_ICON_SIZE 0 @@ -1435,10 +1497,12 @@ typedef enum { BORDER = 0, BASE, TEXT, OTHER } GuiPropertyElement; static GuiState guiState = STATE_NORMAL; // Gui global state, if !STATE_NORMAL, forces defined state static Font guiFont = { 0 }; // Gui current font (WARNING: highly coupled to raylib) +static char guiFontName[32] = { 0 }; // Gui font filename, can be loaded from .rgs (Version: >=600) static bool guiLocked = false; // Gui lock state (no inputs processed) static float guiAlpha = 1.0f; // Gui controls transparency static unsigned int guiIconScale = 1; // Gui icon default scale (if icons enabled) +static unsigned int guiIconFontOffsetY = 0; // Gui icon font atlas offset (if icons backed) static bool guiTooltip = false; // Tooltip enabled/disabled static const char *guiTooltipPtr = NULL; // Tooltip string pointer (string provided by user) @@ -1519,22 +1583,22 @@ static int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle( static void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list static unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle() + +static Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font //------------------------------------------------------------------------------- // raylib functions already implemented in raygui //------------------------------------------------------------------------------- static Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value +static Color Fade(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f static int ColorToInt(Color color); // Returns hexadecimal value for a Color static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed' -static char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings static int TextToInteger(const char *text); // Get integer value from text static float TextToFloat(const char *text); // Get float value from text static int GetCodepointNext(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded text static const char *CodepointToUTF8(int codepoint, int *byteSize); // Encode codepoint into UTF-8 text (char array size returned as parameter) - -static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2); // Draw rectangle vertical gradient //------------------------------------------------------------------------------- #endif // RAYGUI_STANDALONE @@ -1542,22 +1606,22 @@ static void DrawRectangleGradientV(int posX, int posY, int width, int height, Co //---------------------------------------------------------------------------------- // Module Internal Functions Declaration //---------------------------------------------------------------------------------- -static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only) - +static int GetLineWidth(const char *text); // Get text line width (stops at '\n' or '\0') static Rectangle GetTextBounds(int control, Rectangle bounds); // Get text bounds considering control bounds static const char *GetTextIcon(const char *text, int *iconId); // Get text icon if provided and move text cursor -static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint); // Gui draw text using default font -static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // Gui draw rectangle using default raygui style +static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint); // Gui draw text using default font +static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // Gui draw rectangle using default raygui style -static char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow); // Split controls text into multiple strings +static char **GuiTextSplit(const char *text, char delimiter, int *count); // Split controls text into multiple strings static Vector3 ConvertHSVtoRGB(Vector3 hsv); // Convert color data from HSV to RGB static Vector3 ConvertRGBtoHSV(Vector3 rgb); // Convert color data from RGB to HSV -static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel() static void GuiTooltip(Rectangle controlRec); // Draw tooltip using control rec position +static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel() +static int GuiFontIconBaking(Image *imFont, Font font, Rectangle *whiteRec); // Update font image atlas to append raygui icons -static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor +static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor //---------------------------------------------------------------------------------- // Gui Setup Functions Definition @@ -1600,7 +1664,7 @@ void GuiSetFont(Font font) { if (font.texture.id > 0) { - // NOTE: If a font is tried to be set but default style has not been lazily loaded first, + // NOTE: If a font is tried to be set but default style has not been lazily loaded first, // it will be overwritten, so default style loading needs to be forced first if (!guiStyleLoaded) GuiLoadStyleDefault(); @@ -1651,7 +1715,7 @@ int GuiWindowBox(Rectangle bounds, const char *title) #define RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT 18 #endif - int result = 0; + int result = RESULT_NONE; //GuiState state = guiState; int statusBarHeight = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT; @@ -1673,11 +1737,15 @@ int GuiWindowBox(Rectangle bounds, const char *title) // Draw control //-------------------------------------------------------------------- GuiPanel(windowPanel, NULL); // Draw window base + + int tempTextAlignment = GuiGetStyle(STATUSBAR, TEXT_ALIGNMENT); + GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); GuiStatusBar(statusBar, title); // Draw window header as status bar + GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, tempTextAlignment); // Draw window close button int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); - int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); GuiSetStyle(BUTTON, BORDER_WIDTH, 1); GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); #if defined(RAYGUI_NO_ICONS) @@ -1689,7 +1757,7 @@ int GuiWindowBox(Rectangle bounds, const char *title) GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); //-------------------------------------------------------------------- - return result; // Window close button clicked: result = 1 + return result; } // Group Box control with text name @@ -1699,7 +1767,7 @@ int GuiGroupBox(Rectangle bounds, const char *text) #define RAYGUI_GROUPBOX_LINE_THICK 1 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Draw control @@ -1724,7 +1792,7 @@ int GuiLine(Rectangle bounds, const char *text) #define RAYGUI_LINE_TEXT_PADDING 4 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; Color color = GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)); @@ -1757,7 +1825,7 @@ int GuiPanel(Rectangle bounds, const char *text) #define RAYGUI_PANEL_BORDER_WIDTH 1 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Text will be drawn as a header bar (if provided) @@ -1773,7 +1841,7 @@ int GuiPanel(Rectangle bounds, const char *text) // Draw control //-------------------------------------------------------------------- - if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar + if (text != NULL) result = GuiStatusBar(statusBar, text); // Draw panel header as status bar GuiDrawRectangle(bounds, RAYGUI_PANEL_BORDER_WIDTH, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)), GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BASE_COLOR_DISABLED : (int)BACKGROUND_COLOR))); @@ -1782,81 +1850,6 @@ int GuiPanel(Rectangle bounds, const char *text) return result; } -// Tab Bar control -// NOTE: Using GuiToggle() for the TABS -int GuiTabBar(Rectangle bounds, char **text, int count, int *active) -{ - #define RAYGUI_TABBAR_ITEM_WIDTH 148 - - int result = -1; - //GuiState state = guiState; - - Rectangle tabBounds = { bounds.x, bounds.y, RAYGUI_TABBAR_ITEM_WIDTH, bounds.height }; - - if (*active < 0) *active = 0; - else if (*active > count - 1) *active = count - 1; - - int offsetX = 0; // Required in case tabs go out of screen - offsetX = (*active + 2)*RAYGUI_TABBAR_ITEM_WIDTH - GetScreenWidth(); - if (offsetX < 0) offsetX = 0; - - bool toggle = false; // Required for individual toggles - - // Draw control - //-------------------------------------------------------------------- - for (int i = 0; i < count; i++) - { - tabBounds.x = bounds.x + (RAYGUI_TABBAR_ITEM_WIDTH + 4)*i - offsetX; - - if (tabBounds.x < GetScreenWidth()) - { - // Draw tabs as toggle controls - int textAlignment = GuiGetStyle(TOGGLE, TEXT_ALIGNMENT); - int textPadding = GuiGetStyle(TOGGLE, TEXT_PADDING); - GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); - GuiSetStyle(TOGGLE, TEXT_PADDING, 8); - - if (i == (*active)) - { - toggle = true; - GuiToggle(tabBounds, text[i], &toggle); - } - else - { - toggle = false; - GuiToggle(tabBounds, text[i], &toggle); - if (toggle) *active = i; - } - - // Close tab with middle mouse button pressed - if (CheckCollisionPointRec(GUI_POINTER_POSITION, tabBounds) && IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON)) result = i; - - GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding); - GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment); - - // Draw tab close button - // NOTE: Only draw close button for current tab: if (CheckCollisionPointRec(mousePosition, tabBounds)) - int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); - int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); - GuiSetStyle(BUTTON, BORDER_WIDTH, 1); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); -#if defined(RAYGUI_NO_ICONS) - if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, "x")) result = i; -#else - if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, GuiIconText(ICON_CROSS_SMALL, NULL))) result = i; -#endif - GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); - } - } - - // Draw tab-bar bottom line - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, 1 }, 0, BLANK, GetColor(GuiGetStyle(TOGGLE, BORDER_COLOR_NORMAL))); - //-------------------------------------------------------------------- - - return result; // Return as result the current TAB closing requested -} - // Scroll Panel control int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view) { @@ -1864,7 +1857,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector #define RAYGUI_MIN_SCROLLBAR_HEIGHT 40 #define RAYGUI_MIN_MOUSE_WHEEL_SPEED 20 - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; Rectangle temp = { 0 }; @@ -1921,7 +1914,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector float horizontalMin = hasHorizontalScrollBar? ((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH); float horizontalMax = hasHorizontalScrollBar? content.width - bounds.width + (float)verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH) - (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)verticalScrollBarWidth : 0) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); - float verticalMin = hasVerticalScrollBar? 0.0f : -1.0f; + float verticalMin = -(float)GuiGetStyle(DEFAULT, BORDER_WIDTH); float verticalMax = hasVerticalScrollBar? content.height - bounds.height + (float)horizontalScrollBarWidth + (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); // Update control @@ -1971,7 +1964,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector // Draw control //-------------------------------------------------------------------- - if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar + if (text != NULL) result = GuiStatusBar(statusBar, text); // Draw panel header as status bar GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background @@ -2018,7 +2011,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector // Label control int GuiLabel(Rectangle bounds, const char *text) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Update control @@ -2037,7 +2030,7 @@ int GuiLabel(Rectangle bounds, const char *text) // Button control, returns true when clicked int GuiButton(Rectangle bounds, const char *text) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Update control @@ -2052,7 +2045,7 @@ int GuiButton(Rectangle bounds, const char *text) if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; - if (GUI_BUTTON_RELEASED) result = 1; + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; } } //-------------------------------------------------------------------- @@ -2065,14 +2058,14 @@ int GuiButton(Rectangle bounds, const char *text) if (state == STATE_FOCUSED) GuiTooltip(bounds); //------------------------------------------------------------------ - return result; // Button pressed: result = 1 + return result; } // Label button control int GuiLabelButton(Rectangle bounds, const char *text) { + int result = RESULT_NONE; GuiState state = guiState; - bool pressed = false; // NOTE: Force bounds.width to be all text float textWidth = (float)GuiGetTextWidth(text); @@ -2090,7 +2083,7 @@ int GuiLabelButton(Rectangle bounds, const char *text) if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; - if (GUI_BUTTON_RELEASED) pressed = true; + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; } } //-------------------------------------------------------------------- @@ -2100,13 +2093,13 @@ int GuiLabelButton(Rectangle bounds, const char *text) GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); //-------------------------------------------------------------------- - return pressed; + return result; } // Toggle Button control int GuiToggle(Rectangle bounds, const char *text, bool *active) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; bool temp = false; @@ -2126,6 +2119,8 @@ int GuiToggle(Rectangle bounds, const char *text, bool *active) { state = STATE_NORMAL; *active = !(*active); + + result = RESULT_CHANGED; } else state = STATE_FOCUSED; } @@ -2154,68 +2149,110 @@ int GuiToggle(Rectangle bounds, const char *text, bool *active) // Toggle Group control int GuiToggleGroup(Rectangle bounds, const char *text, int *active) { - #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEMS) - #define RAYGUI_TOGGLEGROUP_MAX_ITEMS 32 + int result = RESULT_NONE; + + #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE) + #define RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE 256 #endif - int result = 0; - float initBoundsX = bounds.x; + // One toggle group item text + static char itemText[RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE] = { 0 }; + memset(itemText, 0, RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE); int temp = 0; + int prevActive = (active == NULL)? 0 : *active; if (active == NULL) active = &temp; bool toggle = false; // Required for individual toggles - // Get substrings items from text (items pointers) - int rows[RAYGUI_TOGGLEGROUP_MAX_ITEMS] = { 0 }; - int itemCount = 0; - char **items = GuiTextSplit(text, ';', &itemCount, rows); + const char *textPtr = text; + bool itemReady = false; + float initBoundsX = bounds.x; + float initBoundsY = bounds.y; - int prevRow = rows[0]; - - for (int i = 0; i < itemCount; i++) + if (GuiGetStyle(TOGGLE, GROUP_WIDTH_FULL)) { - if (prevRow != rows[i]) - { - bounds.x = initBoundsX; - bounds.y += (bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING)); - prevRow = rows[i]; - } + // Calculate item width considring all horizontal items + // NOTE: bounds.height still considers individual items height + int itemCount = 1; + for (int c = 0; textPtr[c] != '\0'; c++) { if (textPtr[c] == ';') itemCount++; } + bounds.width /= itemCount; + } - if (i == (*active)) + // Text parsing needed to consider potential row and col entries (vertical/horizontal layout) + // when '\n' found move vertically next toggle, when ';' found move horizontally + for (int c = 0, k = 0, itemIndex = 0, row = 0, col = 0, exit = 0; exit == 0; c++) + { + // Process text to get items one by one + // NOTE: Setting columns and rows index properly + if (textPtr[c] == '\n') { - toggle = true; - GuiToggle(bounds, items[i], &toggle); + row++; + col = 0; + itemReady = true; + } + else if (textPtr[c] == ';') + { + col++; + itemReady = true; + } + else if (textPtr[c] == '\0') + { + itemReady = true; + exit = 1; } else { - toggle = false; - GuiToggle(bounds, items[i], &toggle); - if (toggle) *active = i; + itemText[k] = textPtr[c]; + k++; } - bounds.x += (bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING)); + if (itemReady) + { + // When a next item is ready, draw its toggle + if (itemIndex == (*active)) + { + toggle = true; + GuiToggle(bounds, itemText, &toggle); + } + else + { + toggle = false; + GuiToggle(bounds, itemText, &toggle); + if (toggle) *active = itemIndex; + } + + // Calculate next item position + bounds.x = initBoundsX + col*(bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING)); + bounds.y = initBoundsY + row*(bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING)); + + itemIndex++; + itemReady = false; + memset(itemText, 0, k + 1); + k = 0; + } } + if (prevActive != *active) result = RESULT_CHANGED; + return result; } // Toggle Slider control extended int GuiToggleSlider(Rectangle bounds, const char *text, int *active) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; int temp = 0; + int prevActive = (active == NULL)? 0 : *active; if (active == NULL) active = &temp; - //bool toggle = false; // Required for individual toggles - // Get substrings items from text (items pointers) int itemCount = 0; char **items = NULL; - if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL); + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount); Rectangle slider = { 0, // Calculated later depending on the active toggle @@ -2246,6 +2283,8 @@ int GuiToggleSlider(Rectangle bounds, const char *text, int *active) if (*active >= itemCount) *active = 0; slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH) + (*active + 1)*GuiGetStyle(SLIDER, SLIDER_PADDING) + (*active)*slider.width; + + if (prevActive != *active) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -2277,7 +2316,7 @@ int GuiToggleSlider(Rectangle bounds, const char *text, int *active) // Check Box control, returns 1 when state changed int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; bool temp = false; @@ -2316,7 +2355,8 @@ int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) if (GUI_BUTTON_RELEASED) { *checked = !(*checked); - result = 1; + + result = RESULT_CHANGED; } } } @@ -2344,10 +2384,11 @@ int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) // Combo Box control int GuiComboBox(Rectangle bounds, const char *text, int *active) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; int temp = 0; + int prevActive = (active == NULL)? 0 : *active; if (active == NULL) active = &temp; bounds.width -= (GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH) + GuiGetStyle(COMBOBOX, COMBO_BUTTON_SPACING)); @@ -2357,7 +2398,7 @@ int GuiComboBox(Rectangle bounds, const char *text, int *active) // Get substrings items from text (items pointers, lengths and count) int itemCount = 0; - char **items = GuiTextSplit(text, ';', &itemCount, NULL); + char **items = GuiTextSplit(text, ';', &itemCount); if (*active < 0) *active = 0; else if (*active > (itemCount - 1)) *active = itemCount - 1; @@ -2371,16 +2412,18 @@ int GuiComboBox(Rectangle bounds, const char *text, int *active) if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + if (GUI_BUTTON_PRESSED) { *active += 1; if (*active >= itemCount) *active = 0; // Cyclic combobox } - - if (GUI_BUTTON_DOWN) state = STATE_PRESSED; - else state = STATE_FOCUSED; } } + + if (prevActive != *active) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -2409,10 +2452,11 @@ int GuiComboBox(Rectangle bounds, const char *text, int *active) // NOTE: Returns mouse click int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; int temp = 0; + int prevActive = (active == NULL)? 0 : *active; if (active == NULL) active = &temp; int itemSelected = *active; @@ -2423,7 +2467,7 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod // Get substrings items from text (items pointers, lengths and count) int itemCount = 0; - char **items = GuiTextSplit(text, ';', &itemCount, NULL); + char **items = GuiTextSplit(text, ';', &itemCount); Rectangle boundsOpen = bounds; boundsOpen.height = (itemCount + 1)*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); @@ -2523,7 +2567,8 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 }, TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); #else - GuiDrawText(direction? "#121#" : "#120#", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 }, + GuiDrawText(direction? GuiIconText(ICON_ARROW_UP_FILL, NULL) : GuiIconText(ICON_ARROW_DOWN_FILL, NULL), + RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 }, TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); // ICON_ARROW_DOWN_FILL #endif } @@ -2531,8 +2576,9 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod *active = itemSelected; - // TODO: Use result to return more internal states: mouse-press out-of-bounds, mouse-press over selected-item... - return result; // Mouse click: result = 1 + if (prevActive != *active) result = RESULT_CHANGED; + + return result; } // Text Box control @@ -2546,10 +2592,10 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) #define RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY 1 // Frames delay for autocursor movement #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; - bool multiline = false; // TODO: Consider multiline text input + bool multiline = false; int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); Rectangle textBounds = GetTextBounds(TEXTBOX, bounds); @@ -2596,7 +2642,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) { // GLOBAL: Auto-cursor movement logic // NOTE: Keystrokes are handled repeatedly when button is held down for some time - if (GUI_KEY_DOWN(KEY_LEFT) || GUI_KEY_DOWN(KEY_RIGHT) || GUI_KEY_DOWN(KEY_UP) || GUI_KEY_DOWN(KEY_DOWN) || GUI_KEY_DOWN(KEY_BACKSPACE) || GUI_KEY_DOWN(KEY_DELETE)) autoCursorCounter++; + if (GUI_KEY_DOWN(KEY_LEFT) || GUI_KEY_DOWN(KEY_RIGHT) || + GUI_KEY_DOWN(KEY_UP) || GUI_KEY_DOWN(KEY_DOWN) || + GUI_KEY_DOWN(KEY_BACKSPACE) || GUI_KEY_DOWN(KEY_DELETE)) autoCursorCounter++; else autoCursorCounter = 0; bool autoCursorShouldTrigger = (autoCursorCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN) && ((autoCursorCounter % RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0); @@ -2654,6 +2702,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) textBoxCursorIndex += pasteLength; textLength += pasteLength; text[textLength] = '\0'; + + //result = RESULT_CHANGED; } } } @@ -2672,6 +2722,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) // Make sure text last character is EOL text[textLength] = '\0'; + + //result = RESULT_CHANGED; } // Move cursor to start @@ -2694,8 +2746,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) bool puctuation = ispunct(nextCodepoint & 0xff); while (offset < textLength) { - if ((puctuation && !ispunct(nextCodepoint & 0xff)) || (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff)))) - break; + if ((puctuation && !ispunct(nextCodepoint & 0xff)) || + (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff)))) break; + offset += nextCodepointSize; accCodepointSize += nextCodepointSize; nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); @@ -2715,9 +2768,11 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) for (int i = offset; i <= textLength; i++) text[i - accCodepointSize] = text[i]; textLength -= accCodepointSize; - } - else if ((textLength > textBoxCursorIndex) && (GUI_KEY_PRESSED(KEY_DELETE) || (GUI_KEY_DOWN(KEY_DELETE) && autoCursorShouldTrigger))) + //result = RESULT_CHANGED; + } + else if ((textLength > textBoxCursorIndex) && (GUI_KEY_PRESSED(KEY_DELETE) || + (GUI_KEY_DOWN(KEY_DELETE) && autoCursorShouldTrigger))) { // Delete single codepoint from text, after current cursor position @@ -2728,10 +2783,13 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) for (int i = textBoxCursorIndex + nextCodepointSize; i <= textLength; i++) text[i - nextCodepointSize] = text[i]; textLength -= nextCodepointSize; + + //result = RESULT_CHANGED; } // Delete related codepoints from text, before current cursor position - if ((textBoxCursorIndex > 0) && GUI_KEY_PRESSED(KEY_BACKSPACE) && (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) + if ((textBoxCursorIndex > 0) && GUI_KEY_PRESSED(KEY_BACKSPACE) && + (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) { int offset = textBoxCursorIndex; int accCodepointSize = 0; @@ -2754,7 +2812,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) while (offset > 0) { prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize); - if ((puctuation && !ispunct(prevCodepoint & 0xff)) || (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break; + if ((puctuation && !ispunct(prevCodepoint & 0xff)) || + (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break; offset -= prevCodepointSize; accCodepointSize += prevCodepointSize; @@ -2765,8 +2824,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) textLength -= accCodepointSize; textBoxCursorIndex -= accCodepointSize; - } + //result = RESULT_CHANGED; + } else if ((textBoxCursorIndex > 0) && (GUI_KEY_PRESSED(KEY_BACKSPACE) || (GUI_KEY_DOWN(KEY_BACKSPACE) && autoCursorShouldTrigger))) { // Delete single codepoint from text, before current cursor position @@ -2780,6 +2840,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) textLength -= prevCodepointSize; textBoxCursorIndex -= prevCodepointSize; + + //result = RESULT_CHANGED; } // Move cursor position with keys @@ -2862,7 +2924,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) } // Move cursor position with mouse - if (CheckCollisionPointRec(mousePosition, textBounds)) // Mouse hover text + if (CheckCollisionPointRec(mousePosition, textBounds)) { float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/(float)guiFont.baseSize; int codepointIndex = 0; @@ -2915,7 +2977,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) { textBoxCursorIndex = 0; // GLOBAL: Reset the shared cursor index autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes - result = 1; + + //*editMode = false; + result = RESULT_PRESSED; } } else @@ -2928,7 +2992,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) { textBoxCursorIndex = textLength; // GLOBAL: Place cursor index to the end of current text autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes - result = 1; + + //*editMode = true; + result = RESULT_PRESSED; } } } @@ -2963,7 +3029,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) else if (state == STATE_FOCUSED) GuiTooltip(bounds); //-------------------------------------------------------------------- - return result; // Mouse button pressed: result = 1 + return result; } /* @@ -3061,21 +3127,24 @@ int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); //-------------------------------------------------------------------- + //if (tempValue != *value) result = RESULT_CHANGED; // WARNING: Stops editing + *value = tempValue; + return result; } // Value Box control, updates input text with numbers -// NOTE: Requires static variables: frameCounter int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) { #if !defined(RAYGUI_VALUEBOX_MAX_CHARS) #define RAYGUI_VALUEBOX_MAX_CHARS 32 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; + //int prevValue = *value; char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = { 0 }; snprintf(textValue, RAYGUI_VALUEBOX_MAX_CHARS + 1, "%i", *value); @@ -3162,7 +3231,7 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in if (*value > maxValue) *value = maxValue; else if (*value < minValue) *value = minValue; - result = 1; + result = RESULT_PRESSED; } } else @@ -3173,10 +3242,13 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in if (CheckCollisionPointRec(mousePoint, bounds)) { state = STATE_FOCUSED; - if (GUI_BUTTON_PRESSED) result = 1; + + if (GUI_BUTTON_PRESSED) result = RESULT_PRESSED; } } } + + //if (prevValue != *value) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3207,18 +3279,16 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in } // Floating point Value Box control, updates input val_str with numbers -// NOTE: Requires static variables: frameCounter int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode) { #if !defined(RAYGUI_VALUEBOX_MAX_CHARS) #define RAYGUI_VALUEBOX_MAX_CHARS 32 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; - //char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0"; - //snprintf(textValue, sizeof(textValue), "%2.2f", *value); + //float prevValue = *value; Rectangle textBounds = { 0 }; if (text != NULL) @@ -3303,17 +3373,21 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float if (valueHasChanged) *value = TextToFloat(textValue); - if ((GUI_KEY_PRESSED(KEY_ENTER) || GUI_KEY_PRESSED(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && GUI_BUTTON_PRESSED)) result = 1; + if ((GUI_KEY_PRESSED(KEY_ENTER) || GUI_KEY_PRESSED(KEY_KP_ENTER)) || + (!CheckCollisionPointRec(mousePoint, bounds) && GUI_BUTTON_PRESSED)) result = RESULT_PRESSED; } else { if (CheckCollisionPointRec(mousePoint, bounds)) { state = STATE_FOCUSED; - if (GUI_BUTTON_PRESSED) result = 1; + + if (GUI_BUTTON_PRESSED) result = RESULT_PRESSED; } } } + + //if (prevValue != *value) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3336,8 +3410,7 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float } // Draw text label if provided - GuiDrawText(text, textBounds, - (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, + GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); //-------------------------------------------------------------------- @@ -3348,12 +3421,13 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float // NOTE: Other GuiSlider*() controls use this one int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; float temp = (maxValue - minValue)/2.0f; if (value == NULL) value = &temp; - float oldValue = *value; + + float prevValue = *value; int sliderWidth = GuiGetStyle(SLIDER, SLIDER_WIDTH); @@ -3404,10 +3478,6 @@ int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, flo else if (*value < minValue) *value = minValue; } - // Control value change check - if (oldValue == *value) result = 0; - else result = 1; - // Slider bar limits check float sliderValue = (((*value - minValue)/(maxValue - minValue))*(bounds.width - sliderWidth - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))); if (sliderWidth > 0) // Slider @@ -3423,6 +3493,8 @@ int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, flo slider.width = sliderValue; if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH); } + + if (prevValue != *value) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3465,7 +3537,7 @@ int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, flo // Slider Bar control extended, returns selected value int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) { - int result = 0; + int result = RESULT_NONE; int preSliderWidth = GuiGetStyle(SLIDER, SLIDER_WIDTH); GuiSetStyle(SLIDER, SLIDER_WIDTH, 0); result = GuiSlider(bounds, textLeft, textRight, value, minValue, maxValue); @@ -3477,11 +3549,12 @@ int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, // Progress Bar control extended, shows current progress value int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; float temp = (maxValue - minValue)/2.0f; if (value == NULL) value = &temp; + float prevValue = *value; // Progress bar Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), @@ -3494,6 +3567,8 @@ int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight // WARNING: Working with floats could lead to rounding issues if ((state != STATE_DISABLED)) progress.width = ((float)*value/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)); + + if (prevValue != *value) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3564,9 +3639,26 @@ int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight // Status Bar control int GuiStatusBar(Rectangle bounds, const char *text) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check checkbox state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + //if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + //else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; + } + } + //-------------------------------------------------------------------- + // Draw control //-------------------------------------------------------------------- GuiDrawRectangle(bounds, GuiGetStyle(STATUSBAR, BORDER_WIDTH), GetColor(GuiGetStyle(STATUSBAR, BORDER + (state*3))), GetColor(GuiGetStyle(STATUSBAR, BASE + (state*3)))); @@ -3579,7 +3671,7 @@ int GuiStatusBar(Rectangle bounds, const char *text) // Dummy rectangle control, intended for placeholding int GuiDummyRec(Rectangle bounds, const char *text) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Update control @@ -3593,6 +3685,8 @@ int GuiDummyRec(Rectangle bounds, const char *text) { if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; } } //-------------------------------------------------------------------- @@ -3609,25 +3703,26 @@ int GuiDummyRec(Rectangle bounds, const char *text) // List View control int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active) { - int result = 0; + int result = RESULT_NONE; int itemCount = 0; char **items = NULL; - if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL); + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount); result = GuiListViewEx(bounds, items, itemCount, scrollIndex, active, NULL); return result; } -// List View control with extended parameters +// List View control using text entries list and returning focus entry int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; int itemFocused = (focus == NULL)? -1 : *focus; int itemSelected = (active == NULL)? -1 : *active; + int prevActive = (active == NULL)? 0 : *active; // Check if scroll bar is needed bool useScrollBar = false; @@ -3765,35 +3860,132 @@ int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, in if (focus != NULL) *focus = itemFocused; if (scrollIndex != NULL) *scrollIndex = startIndex; + if (prevActive != *active) result = RESULT_CHANGED; + return result; } -// Color Panel control - Color (RGBA) variant +// Tab Bar control +int GuiTabBar(Rectangle bounds, const char *text, int *hscroll, int *active) +{ + int result = RESULT_NONE; + int itemCount = 0; + char **items = NULL; + + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount); + + result = GuiTabBarEx(bounds, items, itemCount, hscroll, active, NULL); + + return result; +} + +// Tab Bar control, using text entries list and returning focus entry +// NOTE: In case of tab close result, consider focused tab +// TODO: Reeplace GuiToggle() usage for custom implementation for the TABS +int GuiTabBarEx(Rectangle bounds, char **text, int count, int *hscroll, int *active, int *focus) +{ + int result = RESULT_NONE; + //GuiState state = guiState; + + int tabItemsWidth = GuiGetStyle(TABBAR, TAB_ITEMS_WIDTH); + Rectangle tabBounds = { bounds.x, bounds.y, (float)tabItemsWidth, bounds.height }; + + if (*active < 0) *active = 0; + else if (*active > count - 1) *active = count - 1; + + int prevActive = (active == NULL)? 0 : *active; + + int offsetX = 0; // Required in case tabs go out of screen + offsetX = (*active*tabItemsWidth) - GetScreenWidth(); + if (offsetX < 0) offsetX = 0; + + bool toggle = false; // Required for individual toggles + + // Draw control + //-------------------------------------------------------------------- + //if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) // TODO: Support disabled + + for (int i = 0; i < count; i++) + { + tabBounds.x = bounds.x + (tabItemsWidth + 4)*i + offsetX; + + if (tabBounds.x < GetScreenWidth()) + { + // Draw tabs as toggle controls + int textAlignment = GuiGetStyle(TOGGLE, TEXT_ALIGNMENT); + int textPadding = GuiGetStyle(TOGGLE, TEXT_PADDING); + GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(TOGGLE, TEXT_PADDING, 8); + + if (i == (*active)) + { + toggle = true; + GuiToggle(tabBounds, text[i], &toggle); + } + else + { + toggle = false; + GuiToggle(tabBounds, text[i], &toggle); + if (toggle) *active = i; + } + + // Close tab with middle mouse button pressed + if (CheckCollisionPointRec(GUI_POINTER_POSITION, tabBounds) && GUI_BUTTON_PRESSED_MID) result = RESULT_TAB_CLOSE; + + GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding); + GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment); + + if (GuiGetStyle(TABBAR, TAB_CLOSE_BUTTON)) + { + // Draw tab close button + // NOTE: Only draw close button for current tab: if (CheckCollisionPointRec(mousePosition, tabBounds)) + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 1); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); +#if defined(RAYGUI_NO_ICONS) + if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, "x")) result = RESULT_TAB_CLOSE; +#else + if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, + GuiIconText(ICON_CROSS_SMALL, NULL))) result = RESULT_TAB_CLOSE; +#endif + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); + } + } + } + + // Draw tab-bar bottom line + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, 1 }, 0, BLANK, GetColor(GuiGetStyle(TABBAR, BORDER_COLOR_NORMAL))); + //-------------------------------------------------------------------- + + // NOTE: In case of tab close result, consider focused tab + if ((result != RESULT_TAB_CLOSE) && (prevActive != *active)) result = RESULT_CHANGED; + + return result; +} + +// Color Panel control int GuiColorPanel(Rectangle bounds, const char *text, Color *color) { - int result = 0; + int result = RESULT_NONE; Vector3 vcolor = { (float)color->r/255.0f, (float)color->g/255.0f, (float)color->b/255.0f }; Vector3 hsv = ConvertRGBtoHSV(vcolor); - Vector3 prevHsv = hsv; // workaround to see if GuiColorPanelHSV modifies the hsv + Vector3 prevHsv = hsv; // NOTE: Workaround to see if GuiColorPanelHSV() modifies the hsv - GuiColorPanelHSV(bounds, text, &hsv); + result = GuiColorPanelHSV(bounds, text, &hsv); // Check if the hsv was changed, only then change the color // This is required, because the Color->HSV->Color conversion has precision errors // Thus the assignment from HSV to Color should only be made, if the HSV has a new user-entered value // Otherwise GuiColorPanel would often modify it's color without user input - // TODO: GuiColorPanelHSV could return 1 if the slider was dragged, to simplify this check - if (hsv.x != prevHsv.x || hsv.y != prevHsv.y || hsv.z != prevHsv.z) + if ((hsv.x != prevHsv.x) || (hsv.y != prevHsv.y) || (hsv.z != prevHsv.z)) { Vector3 rgb = ConvertHSVtoRGB(hsv); - - // NOTE: Vector3ToColor() only available on raylib 1.8.1 - *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x), - (unsigned char)(255.0f*rgb.y), - (unsigned char)(255.0f*rgb.z), - color->a }; + *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x), (unsigned char)(255.0f*rgb.y), (unsigned char)(255.0f*rgb.z), color->a }; } + return result; } @@ -3805,8 +3997,10 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) #define RAYGUI_COLORBARALPHA_CHECKED_SIZE 10 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; + + float prevAlpha = *alpha; Rectangle selector = { (float)bounds.x + (*alpha)*bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.y - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT), @@ -3853,6 +4047,8 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) else state = STATE_FOCUSED; } } + + if (prevAlpha != *alpha) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3893,8 +4089,10 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) // float GuiColorBarLuminance() [BLACK->WHITE] int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; + + float prevHue = *hue; Rectangle selector = { (float)bounds.x - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)bounds.y + (*hue)/360.0f*bounds.height - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2, (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT) }; // Update control @@ -3949,6 +4147,8 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) }*/ } } + + if (prevHue != *hue) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3956,15 +4156,32 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) if (state != STATE_DISABLED) { // Draw hue bar:color bars - // TODO: Use directly DrawRectangleGradientEx(bounds, color1, color2, color2, color1); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + bounds.height/6), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 2*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 3*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 4*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 5*(bounds.height/6)), (int)bounds.width, (int)(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha)); + // NOTE: Using DrawRectangleGradientEx(bounds, color1, color2, color2, color1); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 1*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 2*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 3*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 4*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 5*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha)); + } + else + { + DrawRectangleGradientEx(bounds, + Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), + Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha)); } - else DrawRectangleGradientV((int)bounds.x, (int)bounds.y, (int)bounds.width, (int)bounds.height, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha)); GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); @@ -3984,12 +4201,12 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) // NOTE: this picker converts RGB to HSV, which can cause the Hue control to jump. If you have this problem, consider using the HSV variant instead int GuiColorPicker(Rectangle bounds, const char *text, Color *color) { - int result = 0; + int result = RESULT_NONE; Color temp = { 200, 0, 0, 255 }; if (color == NULL) color = &temp; - GuiColorPanel(bounds, NULL, color); + result = GuiColorPanel(bounds, NULL, color); Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; //Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) }; @@ -3997,7 +4214,7 @@ int GuiColorPicker(Rectangle bounds, const char *text, Color *color) // NOTE: this conversion can cause low hue-resolution, if the r, g and b value are very similar, which causes the hue bar to shift around when only the GuiColorPanel is used Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ (*color).r/255.0f, (*color).g/255.0f, (*color).b/255.0f }); - GuiColorBarHue(boundsHue, NULL, &hsv.x); + if (result != RESULT_CHANGED) result = GuiColorBarHue(boundsHue, NULL, &hsv.x); //color.a = (unsigned char)(GuiColorBarAlpha(boundsAlpha, (float)color.a/255.0f)*255.0f); Vector3 rgb = ConvertHSVtoRGB(hsv); @@ -4016,7 +4233,7 @@ int GuiColorPicker(Rectangle bounds, const char *text, Color *color) // NOTE: bounds define GuiColorPanelHSV() size int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) { - int result = 0; + int result = RESULT_NONE; Vector3 tempHsv = { 0 }; @@ -4027,11 +4244,11 @@ int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) colorHsv = &tempHsv; } - GuiColorPanelHSV(bounds, NULL, colorHsv); + result = GuiColorPanelHSV(bounds, NULL, colorHsv); - const Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; + Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; - GuiColorBarHue(boundsHue, NULL, &colorHsv->x); + if (result == RESULT_NONE) result = GuiColorBarHue(boundsHue, NULL, &colorHsv->x); return result; } @@ -4039,10 +4256,11 @@ int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) // Color Panel control - HSV variant int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; - Vector2 pickerSelector = { 0 }; + Vector3 prevColorHsv = *colorHsv; + Vector2 pickerSelector = { 0 }; const Color colWhite = { 255, 255, 255, 255 }; const Color colBlack = { 0, 0, 0, 255 }; @@ -4051,9 +4269,7 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) Vector3 maxHue = { colorHsv->x, 1.0f, 1.0f }; Vector3 rgbHue = ConvertHSVtoRGB(maxHue); - Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x), - (unsigned char)(255.0f*rgbHue.y), - (unsigned char)(255.0f*rgbHue.z), 255 }; + Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x), (unsigned char)(255.0f*rgbHue.y), (unsigned char)(255.0f*rgbHue.z), 255 }; // Update control //-------------------------------------------------------------------- @@ -4077,12 +4293,11 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) // Calculate color from picker Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y }; - colorPick.x /= (float)bounds.width; // Get normalized value on x - colorPick.y /= (float)bounds.height; // Get normalized value on y + colorPick.x /= (float)bounds.width; // Get normalized value on x + colorPick.y /= (float)bounds.height; // Get normalized value on y colorHsv->y = colorPick.x; colorHsv->z = 1.0f - colorPick.y; - } } else @@ -4112,6 +4327,10 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) else state = STATE_FOCUSED; } } + + if ((prevColorHsv.x != colorHsv->x) || + (prevColorHsv.y != colorHsv->y) || + (prevColorHsv.z != colorHsv->z)) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -4137,7 +4356,8 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) } // Message Box control -int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons) +// NOTE: Button pressed is returned through btnActive parameter, 0 for window close button +int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *btnText, int *btnActive) { #if !defined(RAYGUI_MESSAGEBOX_BUTTON_HEIGHT) #define RAYGUI_MESSAGEBOX_BUTTON_HEIGHT 24 @@ -4146,10 +4366,10 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons #define RAYGUI_MESSAGEBOX_BUTTON_PADDING 12 #endif - int result = -1; // Returns clicked button from buttons list, 0 refers to closed window button + int result = RESULT_NONE; int buttonCount = 0; - char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL); + char **btnTextList = GuiTextSplit(btnText, ';', &buttonCount); Rectangle buttonBounds = { 0 }; buttonBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING; buttonBounds.y = bounds.y + bounds.height - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT - RAYGUI_MESSAGEBOX_BUTTON_PADDING; @@ -4166,7 +4386,11 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons // Draw control //-------------------------------------------------------------------- - if (GuiWindowBox(bounds, title)) result = 0; + if (GuiWindowBox(bounds, title) == RESULT_PRESSED) + { + *btnActive = 0; + result = RESULT_PRESSED; + } int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); @@ -4178,7 +4402,11 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons for (int i = 0; i < buttonCount; i++) { - if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1; + if (GuiButton(buttonBounds, btnTextList[i])) + { + *btnActive = i + 1; + result = RESULT_PRESSED; + } buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING); } @@ -4188,8 +4416,9 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons return result; } -// Text Input Box control, ask for text -int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive) +// Text Input Box control +// NOTE: Button pressed is returned through btnActive parameter, 0 for window close button +int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, char *text, int textSize, const char *btnText, int *btnActive, bool *secretViewActive) { #if !defined(RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT) #define RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT 24 @@ -4201,14 +4430,14 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co #define RAYGUI_TEXTINPUTBOX_HEIGHT 26 #endif + int result = RESULT_NONE; + // Used to enable text edit mode // WARNING: No more than one GuiTextInputBox() should be open at the same time static bool textEditMode = false; - int result = -1; - int buttonCount = 0; - char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL); + char **btnTextList = GuiTextSplit(btnText, ';', &buttonCount); Rectangle buttonBounds = { 0 }; buttonBounds.x = bounds.x + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; buttonBounds.y = bounds.y + bounds.height - RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; @@ -4238,7 +4467,11 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co // Draw control //-------------------------------------------------------------------- - if (GuiWindowBox(bounds, title)) result = 0; + if (GuiWindowBox(bounds, title) == RESULT_PRESSED) + { + *btnActive = 0; + result = RESULT_PRESSED; + } // Draw message if available if (message != NULL) @@ -4256,13 +4489,20 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co { static char stars[] = "****************"; if (GuiTextBox(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x, textBoxBounds.y, textBoxBounds.width - 4 - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.height }, - ((*secretViewActive == 1) || textEditMode)? text : stars, textMaxSize, textEditMode)) textEditMode = !textEditMode; + ((*secretViewActive == 1) || textEditMode)? text : stars, textSize, textEditMode) == RESULT_PRESSED) textEditMode = !textEditMode; - GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, (*secretViewActive == 1)? "#44#" : "#45#", secretViewActive); +#if defined(RAYGUI_NO_ICONS) + GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, + (*secretViewActive == 1)? "O" : "*", secretViewActive); +#else + GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, + (*secretViewActive == 1)? GuiIconText(ICON_EYE_ON, NULL) : GuiIconText(ICON_EYE_OFF, NULL), secretViewActive); +#endif } else { - if (GuiTextBox(textBoxBounds, text, textMaxSize, textEditMode)) textEditMode = !textEditMode; + if (GuiTextBox(textBoxBounds, text, textSize, textEditMode) == RESULT_PRESSED) + textEditMode = !textEditMode; } GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, prevTextBoxAlignment); @@ -4272,16 +4512,21 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co for (int i = 0; i < buttonCount; i++) { - if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1; + if (GuiButton(buttonBounds, btnTextList[i])) + { + *btnActive = i + 1; + result = RESULT_PRESSED; + } + buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING); } - if (result >= 0) textEditMode = false; + if (result == RESULT_PRESSED) textEditMode = false; GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevBtnTextAlignment); //-------------------------------------------------------------------- - return result; // Result is the pressed button index + return result; } // Grid control @@ -4295,7 +4540,7 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect #define RAYGUI_GRID_ALPHA 0.15f #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; Vector2 mousePoint = GUI_POINTER_POSITION; @@ -4316,6 +4561,8 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect // NOTE: Cell values must be the upper left of the cell the mouse is in currentMouseCell.x = floorf((mousePoint.x - bounds.x)/spacing); currentMouseCell.y = floorf((mousePoint.y - bounds.y)/spacing); + + result = RESULT_PRESSED; } } //-------------------------------------------------------------------- @@ -4342,6 +4589,7 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect } if (mouseCell != NULL) *mouseCell = currentMouseCell; + return result; } @@ -4385,11 +4633,16 @@ void GuiLoadStyle(const char *fileName) int controlId = 0; int propertyId = 0; unsigned int propertyValue = 0; + unsigned int version = 0; while (!feof(rgsFile)) { switch (buffer[0]) { + case 'v': + { + sscanf(buffer, "v %d", &version); + } case 'p': { // Style property: p @@ -4400,12 +4653,17 @@ void GuiLoadStyle(const char *fileName) } break; case 'f': { - // Style font: f + // Style font: f int fontSize = 0; - char charmapFileName[256] = { 0 }; - char fontFileName[256] = { 0 }; - sscanf(buffer, "f %d %s %[^\r\n]s", &fontSize, charmapFileName, fontFileName); + char charmapFileName[32] = { 0 }; + char fontFileName[32] = { 0 }; + + if (version >= 600) sscanf(buffer, "f %d %31s %31[^\r\n]s", &fontSize, fontFileName, charmapFileName); + else sscanf(buffer, "f %d %31s %31[^\r\n]s", &fontSize, charmapFileName, fontFileName); + + // GLOBAL: Copy font file name into guiFontName + snprintf(guiFontName, 32, "%s", fontFileName); Font font = { 0 }; int *codepoints = NULL; @@ -4481,6 +4739,318 @@ void GuiLoadStyle(const char *fileName) } } +// Load style from memory +// WARNING: Binary files only +void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize) +{ + // Style File Structure (.rgs) + // ------------------------------------------------------ + // Offset | Size | Type | Description + // ------------------------------------------------------ + // 0 | 4 | char | Signature: "rGS " + // 4 | 2 | short | Version: 200, 400, 600 + // 6 | 2 | short | reserved + // 8 | 4 | int | Num properties (only changed ones from default style) + + // Properties Data (8 bytes per property) + // WARNING: Only properties required that differ from default (light) internal style + // foreach (property) + // { + // 8+8*i | 2 | short | ControlId + // 8+8*i | 2 | short | PropertyId + // 8+8*i | 4 | int | PropertyValue + // } + + // Custom Font Data : Parameters (64 bytes) + // ... | 4 | int | Font data size (0 - no font, no more fields added!) + // ... | 32 | char | Font filename (with extension) - VERSION: >=600 + // ... | 4 | int | Font base size + // ... | 4 | int | Font glyph count [glyphCount] + // ... | 4 | int | Font type (0-NORMAL, 1-SDF) + // ... | 16 | Rectangle | Font white rectangle + + // Custom Font Data : Image (20 bytes + imData) + // NOTE: Font image atlas is always converted to GRAY+ALPHA + // and atlas image data can be compressed (DEFLATE) + // ... | 4 | int | Image data size (uncompressed) + // ... | 4 | int | Image data size (compressed) + // ... | 4 | int | Image width + // ... | 4 | int | Image height + // ... | 4 | int | Image format: GRAY+ALPHA (expected) + // ... | imSize | byte | Image data (comp or uncomp) + + // Custom Font Data : Recs (32 bytes*glyphCount) + // NOTE: Font recs data can be compressed (DEFLATE) + // ... | 4 | int | Recs data compressed size (0 - not compressed, 1-compressed) - VERSION: >=400 + // + // if (compRecsSize == 0) + // { + // NOTE: Uncompressed size can be calculated: (glyphCount*16 byte) + // foreach (glyph) + // { + // ... | 16 | Rectangle | Glyph rectangle (in image) + // } + // } + // else + // { + // ... | compRecsSize | byte | Rectangles data + // } + // + + // Custom Font Data : Glyph Info (32 bytes*glyphCount) + // NOTE: Font glyphs info data can be compressed (DEFLATE) + // ... | 4 | int | Glyphs data compressed size (0 - not compressed) - VERSION: >=400 + // + // if (compGlyphsSize == 0) + // { + // NOTE: Uncompressed size can be calculated: (glyphCount*16 byte) + // foreach (glyph) + // { + // ... | 4 | int | Glyph value + // ... | 4 | int | Glyph offset X + // ... | 4 | int | Glyph offset Y + // ... | 4 | int | Glyph advance X + // } + // } + // else + // { + // ... | compGlyphsSize | byte | Glyphs data + // } + // ------------------------------------------------------ + + unsigned char *fileDataPtr = (unsigned char *)fileData; + + char signature[5] = { 0 }; + short version = 0; + short reserved = 0; + int propertyCount = 0; + + memcpy(signature, fileDataPtr, 4); + memcpy(&version, fileDataPtr + 4, sizeof(short)); + memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short)); + memcpy(&propertyCount, fileDataPtr + 4 + 2 + 2, sizeof(int)); + fileDataPtr += 12; + + if ((signature[0] == 'r') && + (signature[1] == 'G') && + (signature[2] == 'S') && + (signature[3] == ' ')) + { + short controlId = 0; + short propertyId = 0; + unsigned int propertyValue = 0; + + for (int i = 0; i < propertyCount; i++) + { + memcpy(&controlId, fileDataPtr, sizeof(short)); + memcpy(&propertyId, fileDataPtr + 2, sizeof(short)); + memcpy(&propertyValue, fileDataPtr + 2 + 2, sizeof(unsigned int)); + fileDataPtr += 8; + + if (controlId == 0) // DEFAULT control + { + // If a DEFAULT property is loaded, it is propagated to all controls + // NOTE: All DEFAULT properties should be defined first in the file + GuiSetStyle(0, (int)propertyId, propertyValue); + + if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int j = 1; j < RAYGUI_MAX_CONTROLS; j++) GuiSetStyle(j, (int)propertyId, propertyValue); + } + else GuiSetStyle((int)controlId, (int)propertyId, propertyValue); + } + + // Load custom font if available + // NOTE: Font texture loading requires raylib + int fontDataSize = 0; + memcpy(&fontDataSize, fileDataPtr, sizeof(int)); + fileDataPtr += 4; + + if (fontDataSize > 0) + { + Font font = { 0 }; + int fontType = 0; // 0-Normal, 1-SDF + + // WARNING: Version 600 adds 32 bytes for the font filename (with extension) + if (version >= 600) + { + // GLOBAL: Copy font file name into guiFontName + memcpy(guiFontName, fileDataPtr, 32); + fileDataPtr += 32; + } + else memset(guiFontName, 0, 32); + + memcpy(&font.baseSize, fileDataPtr, sizeof(int)); + memcpy(&font.glyphCount, fileDataPtr + 4, sizeof(int)); + memcpy(&fontType, fileDataPtr + 4 + 4, sizeof(int)); + fileDataPtr += 12; + + // Load font white rectangle + Rectangle fontWhiteRec = { 0 }; + memcpy(&fontWhiteRec, fileDataPtr, sizeof(Rectangle)); + fileDataPtr += 16; + + // Load font image parameters + int fontImageUncompSize = 0; + int fontImageCompSize = 0; + memcpy(&fontImageUncompSize, fileDataPtr, sizeof(int)); + memcpy(&fontImageCompSize, fileDataPtr + 4, sizeof(int)); + fileDataPtr += 8; + + Image imFont = { 0 }; + imFont.mipmaps = 1; + memcpy(&imFont.width, fileDataPtr, sizeof(int)); + memcpy(&imFont.height, fileDataPtr + 4, sizeof(int)); + memcpy(&imFont.format, fileDataPtr + 4 + 4, sizeof(int)); + fileDataPtr += 12; + + if ((fontImageCompSize > 0) && (fontImageCompSize != fontImageUncompSize)) + { + // Compressed font atlas image data (DEFLATE), it requires DecompressData() + int dataUncompSize = 0; + unsigned char *compData = (unsigned char *)RAYGUI_CALLOC(fontImageCompSize, sizeof(unsigned char)); + memcpy(compData, fileDataPtr, fontImageCompSize); + fileDataPtr += fontImageCompSize; + + imFont.data = DecompressData(compData, fontImageCompSize, &dataUncompSize); + + // Security check, dataUncompSize must match the provided fontImageUncompSize + if (dataUncompSize != fontImageUncompSize) RAYGUI_LOG("WARNING: Uncompressed font atlas image data could be corrupted"); + + RAYGUI_FREE(compData); + } + else + { + // Font atlas image data is not compressed + imFont.data = (unsigned char *)RAYGUI_CALLOC(fontImageUncompSize, sizeof(unsigned char)); + memcpy(imFont.data, fileDataPtr, fontImageUncompSize); + fileDataPtr += fontImageUncompSize; + } + + // Load font recs data (glyphs position and size in the image atlas) + int recsDataSize = font.glyphCount*sizeof(Rectangle); + int recsDataCompressedSize = 0; + + // WARNING: Version 400 adds the compression size parameter + if (version >= 400) + { + // RGS files version 400 support compressed recs data + memcpy(&recsDataCompressedSize, fileDataPtr, sizeof(int)); + fileDataPtr += sizeof(int); + } + + if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize)) + { + // Recs data is compressed, uncompress it + unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_CALLOC(recsDataCompressedSize, sizeof(unsigned char)); + + memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize); + fileDataPtr += recsDataCompressedSize; + + int recsDataUncompSize = 0; + font.recs = (Rectangle *)DecompressData(recsDataCompressed, recsDataCompressedSize, &recsDataUncompSize); + + // Security check, data uncompressed size must match the expected original data size + if (recsDataUncompSize != recsDataSize) RAYGUI_LOG("WARNING: Uncompressed font recs data could be corrupted"); + + RAYGUI_FREE(recsDataCompressed); + } + else + { + // Recs data is uncompressed + font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle)); + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.recs[i], fileDataPtr, sizeof(Rectangle)); + fileDataPtr += sizeof(Rectangle); + } + } + + // Load font glyphs info data + int glyphsDataSize = font.glyphCount*16; // 16 bytes data per glyph + int glyphsDataCompressedSize = 0; + + // WARNING: Version 400 adds the compression size parameter + if (version >= 400) + { + // RGS files version 400 support compressed glyphs data + memcpy(&glyphsDataCompressedSize, fileDataPtr, sizeof(int)); + fileDataPtr += sizeof(int); + } + + // Allocate required glyphs space to fill with data + font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo)); + + if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize)) + { + // Glyphs data is compressed, uncompress it + unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_CALLOC(glyphsDataCompressedSize, sizeof(unsigned char)); + + memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize); + fileDataPtr += glyphsDataCompressedSize; + + int glyphsDataUncompSize = 0; + unsigned char *glyphsDataUncomp = DecompressData(glypsDataCompressed, glyphsDataCompressedSize, &glyphsDataUncompSize); + + // Security check, data uncompressed size must match the expected original data size + if (glyphsDataUncompSize != glyphsDataSize) RAYGUI_LOG("WARNING: Uncompressed font glyphs data could be corrupted"); + + unsigned char *glyphsDataUncompPtr = glyphsDataUncomp; + + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.glyphs[i].value, glyphsDataUncompPtr, sizeof(int)); + memcpy(&font.glyphs[i].offsetX, glyphsDataUncompPtr + 4, sizeof(int)); + memcpy(&font.glyphs[i].offsetY, glyphsDataUncompPtr + 8, sizeof(int)); + memcpy(&font.glyphs[i].advanceX, glyphsDataUncompPtr + 12, sizeof(int)); + glyphsDataUncompPtr += 16; + } + + RAYGUI_FREE(glypsDataCompressed); + RAYGUI_FREE(glyphsDataUncomp); + } + else + { + // Glyphs data is uncompressed + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.glyphs[i].value, fileDataPtr, sizeof(int)); + memcpy(&font.glyphs[i].offsetX, fileDataPtr + 4, sizeof(int)); + memcpy(&font.glyphs[i].offsetY, fileDataPtr + 8, sizeof(int)); + memcpy(&font.glyphs[i].advanceX, fileDataPtr + 12, sizeof(int)); + fileDataPtr += 16; + } + } + +#if defined(RAYGUI_FONT_ICONS_BAKING) + // Font atlas image icons baking + Rectangle updatedWhiteRec = { 0 }; + guiIconFontOffsetY = GuiFontIconBaking(&imFont, font, &updatedWhiteRec); + if (guiIconFontOffsetY > 0) fontWhiteRec = updatedWhiteRec; +#endif + +#if !defined(RAYGUI_STANDALONE) + // Load texture from image + if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture); + font.texture = LoadTextureFromImage(imFont); + + // Fallback to default raylib texture if font texture loading fails + if (font.texture.id != 0) + { + // Set font texture source rectangle to be used as white texture to draw shapes + // NOTE: It makes possible to draw shapes and text (full UI) in a single draw call + if ((fontWhiteRec.x > 0) && + (fontWhiteRec.y > 0) && + (fontWhiteRec.width > 0) && + (fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec); + } + else font = GetFontDefault(); + + GuiSetFont(font); +#endif + RAYGUI_FREE(imFont.data); + } + } +} + // Load style default over global style void GuiLoadStyleDefault(void) { @@ -4513,7 +5083,7 @@ void GuiLoadStyleDefault(void) GuiSetStyle(DEFAULT, TEXT_SPACING, 1); // DEFAULT, shared by all controls GuiSetStyle(DEFAULT, LINE_COLOR, 0x90abb5ff); // DEFAULT specific property GuiSetStyle(DEFAULT, BACKGROUND_COLOR, 0xf5f5f5ff); // DEFAULT specific property - GuiSetStyle(DEFAULT, TEXT_LINE_SPACING, 5); // DEFAULT, pixels between lines, from bottom of first line to top of second + GuiSetStyle(DEFAULT, TEXT_LINE_SPACING, 12); // DEFAULT, pixels between lines, from bottom of first line to top of second GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); // DEFAULT, text aligned vertically to middle of text-bounds // Initialize control-specific property values @@ -4532,6 +5102,7 @@ void GuiLoadStyleDefault(void) GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); GuiSetStyle(STATUSBAR, TEXT_PADDING, 8); GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(TABBAR, TAB_ITEMS_WIDTH, 160); // Initialize extended property values // NOTE: By default, extended property values are initialized to 0 @@ -4581,6 +5152,9 @@ void GuiLoadStyleDefault(void) // NOTE: Setting up a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering SetShapesTexture(guiFont.texture, RAYGUI_CLITERAL(Rectangle){ whiteChar.x + 1, whiteChar.y + 1, whiteChar.width - 2, whiteChar.height - 2 }); + + // Reset baked icons offset in font + guiIconFontOffsetY = 0; } } @@ -4622,71 +5196,28 @@ const char *GuiIconText(int iconId, const char *text) unsigned int *GuiGetIcons(void) { return guiIconsPtr; } // Load raygui icons file (.rgi) -// NOTE: In case nameIds are required, they can be requested with loadIconsName, -// they are returned as a guiIconsName[iconCount][RAYGUI_ICON_MAX_NAME_LENGTH], // WARNING: guiIconsName[]][] memory should be manually freed! char **GuiLoadIcons(const char *fileName, bool loadIconsName) { - // Style File Structure (.rgi) - // ------------------------------------------------------ - // Offset | Size | Type | Description - // ------------------------------------------------------ - // 0 | 4 | char | Signature: "rGI " - // 4 | 2 | short | Version: 100 - // 6 | 2 | short | reserved - - // 8 | 2 | short | Num icons (N) - // 10 | 2 | short | Icons size (Options: 16, 32, 64) (S) - - // Icons name id (32 bytes per name id) - // foreach (icon) - // { - // 12+32*i | 32 | char | Icon NameId - // } - - // Icons data: One bit per pixel, stored as unsigned int array (depends on icon size) - // S*S pixels/32bit per unsigned int = K unsigned int per icon - // foreach (icon) - // { - // ... | K | unsigned int | Icon Data - // } - FILE *rgiFile = fopen(fileName, "rb"); - char **guiIconsName = NULL; if (rgiFile != NULL) { - char signature[5] = { 0 }; - short version = 0; - short reserved = 0; - short iconCount = 0; - short iconSize = 0; + unsigned char *fileData = NULL; + int dataSize = 0; - fread(signature, 1, 4, rgiFile); - fread(&version, sizeof(short), 1, rgiFile); - fread(&reserved, sizeof(short), 1, rgiFile); - fread(&iconCount, sizeof(short), 1, rgiFile); - fread(&iconSize, sizeof(short), 1, rgiFile); + fseek(rgiFile, 0, SEEK_END); + int size = (int)ftell(rgiFile); + fseek(rgiFile, 0, SEEK_SET); - if ((signature[0] == 'r') && - (signature[1] == 'G') && - (signature[2] == 'I') && - (signature[3] == ' ')) + if (size > 0) { - if (loadIconsName) - { - guiIconsName = (char **)RAYGUI_CALLOC(iconCount, sizeof(char *)); - for (int i = 0; i < iconCount; i++) - { - guiIconsName[i] = (char *)RAYGUI_CALLOC(RAYGUI_ICON_MAX_NAME_LENGTH, sizeof(char)); - fread(guiIconsName[i], 1, RAYGUI_ICON_MAX_NAME_LENGTH, rgiFile); - } - } - else fseek(rgiFile, iconCount*RAYGUI_ICON_MAX_NAME_LENGTH, SEEK_CUR); + fileData = (unsigned char *)RL_CALLOC(size, sizeof(unsigned char)); + // WARNING: File can be partially loaded but ignoring it for simplicity + dataSize = (int)fread(fileData, sizeof(unsigned char), size, rgiFile); - // Read icons data directly over internal icons array - fread(guiIconsPtr, sizeof(unsigned int), (int)iconCount*((int)iconSize*(int)iconSize/32), rgiFile); + guiIconsName = GuiLoadIconsFromMemory(fileData, dataSize, loadIconsName); } fclose(rgiFile); @@ -4696,9 +5227,34 @@ char **GuiLoadIcons(const char *fileName, bool loadIconsName) } // Load icons from memory -// WARNING: Binary files only +// GLOBAL: Updates global variable: guiIconsPtr char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName) { + // Icon File Structure (.rgi) + // ------------------------------------------------------ + // Offset | Size | Type | Description + // ------------------------------------------------------ + // 0 | 4 | char | Signature: "rGI " + // 4 | 2 | short | Version: 100, 500 + // 6 | 2 | short | reserved + + // 8 | 2 | short | Num icons (N) + // 10 | 2 | short | Icons Size (Options: 16, 32, 64) + + // Icons name id (32 bytes per name id) + // foreach (icon) + // { + // 12+32*i | 32 | char | Icon NameId + // } + + // Icons data: One bit per pixel, stored as unsigned int array (depends on icon size) + // Size*Size pixels/32bit per unsigned int = K unsigned int per icon + // foreach (icon) + // { + // ... | K | unsigned int | Icon Data + // } + // ------------------------------------------------------ + unsigned char *fileDataPtr = (unsigned char *)fileData; char **guiIconsName = NULL; @@ -4722,7 +5278,8 @@ char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool { if (loadIconsName) { - guiIconsName = (char **)RAYGUI_CALLOC(iconCount, sizeof(char *)); + // NOTE: Always allocating RAYGUI_ICON_MAX_ICONS names slots + guiIconsName = (char **)RAYGUI_CALLOC(RAYGUI_ICON_MAX_ICONS, sizeof(char *)); for (int i = 0; i < iconCount; i++) { guiIconsName[i] = (char *)RAYGUI_CALLOC(RAYGUI_ICON_MAX_NAME_LENGTH, sizeof(char)); @@ -4748,20 +5305,35 @@ char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool // Draw selected icon using rectangles pixel-by-pixel void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color) { - #define BIT_CHECK(a,b) ((a) & (1u<<(b))) - - for (int i = 0, y = 0; i < RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32; i++) + if ((guiIconFontOffsetY > 0) && (iconId < RAYGUI_ICON_MAX_FONT_BACKED)) { - for (int k = 0; k < 32; k++) - { - if (BIT_CHECK(guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i], k)) - { - #if !defined(RAYGUI_STANDALONE) - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize, (float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color); - #endif - } + int maxIconsPerLine = guiFont.texture.width/(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + int x = iconId%maxIconsPerLine; + int y = iconId/maxIconsPerLine; - if ((k == 15) || (k == 31)) y++; + Rectangle srcRec = { (float)x*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + RAYGUI_ICON_FONT_ATLAS_PADDING, + guiIconFontOffsetY + (float)y*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + RAYGUI_ICON_FONT_ATLAS_PADDING, + RAYGUI_ICON_SIZE, RAYGUI_ICON_SIZE }; + Rectangle dstRec = { (float)posX, (float)posY, (float)pixelSize*RAYGUI_ICON_SIZE, (float)pixelSize*RAYGUI_ICON_SIZE }; + + DrawTexturePro(guiFont.texture, srcRec, dstRec, RAYGUI_CLITERAL(Vector2){ 0, 0 }, 0.0f, color); + } + else + { + #define BIT_CHECK(a,b) ((a) & (1u<<(b))) + + for (int i = 0, y = 0; i < RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32; i++) + { + for (int k = 0; k < 32; k++) + { + if (BIT_CHECK(guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i], k)) + { + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize, + (float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color); + } + + if ((k == 15) || (k == 31)) y++; + } } } } @@ -4772,28 +5344,56 @@ void GuiSetIconScale(int scale) if (scale >= 1) guiIconScale = scale; } -// Get text width considering gui style and icon size (if required) +// Get text width considering gui style and icon size (if required). +// For multi-line text (containing '\n'), returns the width of the widest line. int GuiGetTextWidth(const char *text) { - #if !defined(ICON_TEXT_PADDING) - #define ICON_TEXT_PADDING 4 - #endif + if (text == NULL) return 0; + + int maxWidth = 0; + const char *linePtr = text; + + while ((linePtr[0] != '\0') && ((linePtr - text) < MAX_LINE_BUFFER_SIZE)) + { + int lineWidth = GetLineWidth(linePtr); + if (lineWidth > maxWidth) maxWidth = lineWidth; + + // Skip to the next '\n' (or end of string/buffer) + while ((linePtr[0] != '\0') && (linePtr[0] != '\n') && ((linePtr - text) < MAX_LINE_BUFFER_SIZE)) + { + linePtr++; + } + // Advance past the '\n' delimiter to the start of the next line + if (linePtr[0] == '\n') linePtr++; + } + + return maxWidth; +} + +#endif // !RAYGUI_NO_ICONS + +//---------------------------------------------------------------------------------- +// Module Internal Functions Definition +//---------------------------------------------------------------------------------- +// Get text line width (stops at '\n' or '\0') +// NOTE: Considers icon marker '#NNN#' +static int GetLineWidth(const char *text) +{ +#if !defined(RAYGUI_ICON_TEXT_PADDING) + #define RAYGUI_ICON_TEXT_PADDING 4 +#endif Vector2 textSize = { 0 }; int textIconOffset = 0; if ((text != NULL) && (text[0] != '\0')) { + // Icon marker: '#' + 1..3 digits + '#' (matches GetTextIcon()) if (text[0] == '#') { - for (int i = 1; (i < 5) && (text[i] != '\0'); i++) - { - if (text[i] == '#') - { - textIconOffset = i; - break; - } - } + int pos = 1; + while ((pos < 4) && (text[pos] >= '0') && (text[pos] <= '9')) pos++; + if (text[pos] == '#') textIconOffset = pos + 1; } text += textIconOffset; @@ -4801,10 +5401,10 @@ int GuiGetTextWidth(const char *text) // Make sure guiFont is set, GuiGetStyle() initializes it lazynessly float fontSize = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - // Custom MeasureText() implementation + // Custom MeasureText() implementation -- single line only if ((guiFont.texture.id > 0) && (text != NULL)) { - // Get size in bytes of text, considering end of line and line break + // Get size in bytes of the line, considering end of line and line break int size = 0; for (int i = 0; i < MAX_LINE_BUFFER_SIZE; i++) { @@ -4828,239 +5428,12 @@ int GuiGetTextWidth(const char *text) } } - if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + ICON_TEXT_PADDING); + if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + RAYGUI_ICON_TEXT_PADDING); } return (int)textSize.x; } -#endif // !RAYGUI_NO_ICONS - -//---------------------------------------------------------------------------------- -// Module Internal Functions Definition -//---------------------------------------------------------------------------------- -// Load style from memory -// WARNING: Binary files only -static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize) -{ - unsigned char *fileDataPtr = (unsigned char *)fileData; - - char signature[5] = { 0 }; - short version = 0; - short reserved = 0; - int propertyCount = 0; - - memcpy(signature, fileDataPtr, 4); - memcpy(&version, fileDataPtr + 4, sizeof(short)); - memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short)); - memcpy(&propertyCount, fileDataPtr + 4 + 2 + 2, sizeof(int)); - fileDataPtr += 12; - - if ((signature[0] == 'r') && - (signature[1] == 'G') && - (signature[2] == 'S') && - (signature[3] == ' ')) - { - short controlId = 0; - short propertyId = 0; - unsigned int propertyValue = 0; - - for (int i = 0; i < propertyCount; i++) - { - memcpy(&controlId, fileDataPtr, sizeof(short)); - memcpy(&propertyId, fileDataPtr + 2, sizeof(short)); - memcpy(&propertyValue, fileDataPtr + 2 + 2, sizeof(unsigned int)); - fileDataPtr += 8; - - if (controlId == 0) // DEFAULT control - { - // If a DEFAULT property is loaded, it is propagated to all controls - // NOTE: All DEFAULT properties should be defined first in the file - GuiSetStyle(0, (int)propertyId, propertyValue); - - if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int j = 1; j < RAYGUI_MAX_CONTROLS; j++) GuiSetStyle(j, (int)propertyId, propertyValue); - } - else GuiSetStyle((int)controlId, (int)propertyId, propertyValue); - } - - // Font loading is highly dependant on raylib API to load font data and image - -#if !defined(RAYGUI_STANDALONE) - // Load custom font if available - int fontDataSize = 0; - memcpy(&fontDataSize, fileDataPtr, sizeof(int)); - fileDataPtr += 4; - - if (fontDataSize > 0) - { - Font font = { 0 }; - int fontType = 0; // 0-Normal, 1-SDF - - memcpy(&font.baseSize, fileDataPtr, sizeof(int)); - memcpy(&font.glyphCount, fileDataPtr + 4, sizeof(int)); - memcpy(&fontType, fileDataPtr + 4 + 4, sizeof(int)); - fileDataPtr += 12; - - // Load font white rectangle - Rectangle fontWhiteRec = { 0 }; - memcpy(&fontWhiteRec, fileDataPtr, sizeof(Rectangle)); - fileDataPtr += 16; - - // Load font image parameters - int fontImageUncompSize = 0; - int fontImageCompSize = 0; - memcpy(&fontImageUncompSize, fileDataPtr, sizeof(int)); - memcpy(&fontImageCompSize, fileDataPtr + 4, sizeof(int)); - fileDataPtr += 8; - - Image imFont = { 0 }; - imFont.mipmaps = 1; - memcpy(&imFont.width, fileDataPtr, sizeof(int)); - memcpy(&imFont.height, fileDataPtr + 4, sizeof(int)); - memcpy(&imFont.format, fileDataPtr + 4 + 4, sizeof(int)); - fileDataPtr += 12; - - if ((fontImageCompSize > 0) && (fontImageCompSize != fontImageUncompSize)) - { - // Compressed font atlas image data (DEFLATE), it requires DecompressData() - int dataUncompSize = 0; - unsigned char *compData = (unsigned char *)RAYGUI_CALLOC(fontImageCompSize, sizeof(unsigned char)); - memcpy(compData, fileDataPtr, fontImageCompSize); - fileDataPtr += fontImageCompSize; - - imFont.data = DecompressData(compData, fontImageCompSize, &dataUncompSize); - - // Security check, dataUncompSize must match the provided fontImageUncompSize - if (dataUncompSize != fontImageUncompSize) RAYGUI_LOG("WARNING: Uncompressed font atlas image data could be corrupted"); - - RAYGUI_FREE(compData); - } - else - { - // Font atlas image data is not compressed - imFont.data = (unsigned char *)RAYGUI_CALLOC(fontImageUncompSize, sizeof(unsigned char)); - memcpy(imFont.data, fileDataPtr, fontImageUncompSize); - fileDataPtr += fontImageUncompSize; - } - - if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture); - font.texture = LoadTextureFromImage(imFont); - - RAYGUI_FREE(imFont.data); - - // Validate font atlas texture was loaded correctly - if (font.texture.id != 0) - { - // Load font recs data - int recsDataSize = font.glyphCount*sizeof(Rectangle); - int recsDataCompressedSize = 0; - - // WARNING: Version 400 adds the compression size parameter - if (version >= 400) - { - // RGS files version 400 support compressed recs data - memcpy(&recsDataCompressedSize, fileDataPtr, sizeof(int)); - fileDataPtr += sizeof(int); - } - - if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize)) - { - // Recs data is compressed, uncompress it - unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_CALLOC(recsDataCompressedSize, sizeof(unsigned char)); - - memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize); - fileDataPtr += recsDataCompressedSize; - - int recsDataUncompSize = 0; - font.recs = (Rectangle *)DecompressData(recsDataCompressed, recsDataCompressedSize, &recsDataUncompSize); - - // Security check, data uncompressed size must match the expected original data size - if (recsDataUncompSize != recsDataSize) RAYGUI_LOG("WARNING: Uncompressed font recs data could be corrupted"); - - RAYGUI_FREE(recsDataCompressed); - } - else - { - // Recs data is uncompressed - font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle)); - for (int i = 0; i < font.glyphCount; i++) - { - memcpy(&font.recs[i], fileDataPtr, sizeof(Rectangle)); - fileDataPtr += sizeof(Rectangle); - } - } - - // Load font glyphs info data - int glyphsDataSize = font.glyphCount*16; // 16 bytes data per glyph - int glyphsDataCompressedSize = 0; - - // WARNING: Version 400 adds the compression size parameter - if (version >= 400) - { - // RGS files version 400 support compressed glyphs data - memcpy(&glyphsDataCompressedSize, fileDataPtr, sizeof(int)); - fileDataPtr += sizeof(int); - } - - // Allocate required glyphs space to fill with data - font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo)); - - if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize)) - { - // Glyphs data is compressed, uncompress it - unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_CALLOC(glyphsDataCompressedSize, sizeof(unsigned char)); - - memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize); - fileDataPtr += glyphsDataCompressedSize; - - int glyphsDataUncompSize = 0; - unsigned char *glyphsDataUncomp = DecompressData(glypsDataCompressed, glyphsDataCompressedSize, &glyphsDataUncompSize); - - // Security check, data uncompressed size must match the expected original data size - if (glyphsDataUncompSize != glyphsDataSize) RAYGUI_LOG("WARNING: Uncompressed font glyphs data could be corrupted"); - - unsigned char *glyphsDataUncompPtr = glyphsDataUncomp; - - for (int i = 0; i < font.glyphCount; i++) - { - memcpy(&font.glyphs[i].value, glyphsDataUncompPtr, sizeof(int)); - memcpy(&font.glyphs[i].offsetX, glyphsDataUncompPtr + 4, sizeof(int)); - memcpy(&font.glyphs[i].offsetY, glyphsDataUncompPtr + 8, sizeof(int)); - memcpy(&font.glyphs[i].advanceX, glyphsDataUncompPtr + 12, sizeof(int)); - glyphsDataUncompPtr += 16; - } - - RAYGUI_FREE(glypsDataCompressed); - RAYGUI_FREE(glyphsDataUncomp); - } - else - { - // Glyphs data is uncompressed - for (int i = 0; i < font.glyphCount; i++) - { - memcpy(&font.glyphs[i].value, fileDataPtr, sizeof(int)); - memcpy(&font.glyphs[i].offsetX, fileDataPtr + 4, sizeof(int)); - memcpy(&font.glyphs[i].offsetY, fileDataPtr + 8, sizeof(int)); - memcpy(&font.glyphs[i].advanceX, fileDataPtr + 12, sizeof(int)); - fileDataPtr += 16; - } - } - } - else font = GetFontDefault(); // Fallback in case of errors loading font atlas texture - - GuiSetFont(font); - - // Set font texture source rectangle to be used as white texture to draw shapes - // NOTE: It makes possible to draw shapes and text (full UI) in a single draw call - if ((fontWhiteRec.x > 0) && - (fontWhiteRec.y > 0) && - (fontWhiteRec.width > 0) && - (fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec); - } -#endif - } -} - // Get text bounds considering control bounds static Rectangle GetTextBounds(int control, Rectangle bounds) { @@ -5081,11 +5454,11 @@ static Rectangle GetTextBounds(int control, Rectangle bounds) case SLIDER: case CHECKBOX: case VALUEBOX: - case CONTROL11: - // TODO: More special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER + case TABBAR: + // TODO: Special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER default: { - // TODO: WARNING: TEXT_ALIGNMENT is already considered in GuiDrawText() + // WARNING: TEXT_ALIGNMENT is already considered in GuiDrawText() if (GuiGetStyle(control, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT) textBounds.x -= GuiGetStyle(control, TEXT_PADDING); else textBounds.x += GuiGetStyle(control, TEXT_PADDING); } @@ -5096,12 +5469,12 @@ static Rectangle GetTextBounds(int control, Rectangle bounds) } // Get text icon if provided and move text cursor -// NOTE: Up to #999# values supported for iconId +// NOTE: Up to RAYGUI_ICON_MAX_ICONS supported for iconId static const char *GetTextIcon(const char *text, int *iconId) { #if !defined(RAYGUI_NO_ICONS) *iconId = -1; - if (text[0] == '#') // Maybe it is stars with an icon, ending # must be found + if (text[0] == '#') // Maybe an icon, if it starts with # but an ending # must be found { char iconValue[4] = { 0 }; // Maximum length for icon value: 3 digits + '\0' @@ -5114,11 +5487,15 @@ static const char *GetTextIcon(const char *text, int *iconId) if (text[pos] == '#') { - *iconId = TextToInteger(iconValue); + int rawIconId = TextToInteger(iconValue); + if (rawIconId < RAYGUI_ICON_MAX_ICONS) + { + *iconId = rawIconId; - // Move text pointer after icon - // WARNING: If only icon provided, it could point to EOL character: '\0' - if (*iconId >= 0) text += (pos + 1); + // Move text pointer after icon + // WARNING: If only icon provided, it could point to EOL character: '\0' + if (*iconId >= 0) text += (pos + 1); + } } } #endif @@ -5186,8 +5563,8 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C { #define TEXT_VALIGN_PIXEL_OFFSET(h) ((int)h%2) // Vertical alignment for pixel perfect - #if !defined(ICON_TEXT_PADDING) - #define ICON_TEXT_PADDING 4 + #if !defined(RAYGUI_ICON_TEXT_PADDING) + #define RAYGUI_ICON_TEXT_PADDING 4 #endif if ((text == NULL) || (text[0] == '\0')) return; // Security check @@ -5223,9 +5600,9 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C Vector2 textBoundsPosition = { textBounds.x, textBounds.y }; float textBoundsWidthOffset = 0.0f; - // NOTE: Get text size after icon has been processed - // WARNING: GuiGetTextWidth() also processes text icon to get width! -> Really needed? - int textSizeX = GuiGetTextWidth(lines[i]); + // NOTE: Icon was already stripped above by GetTextIcon(); GetLineWidth() + // takes no icon path here and returns only the glyph width of this line. + int textSizeX = GetLineWidth(lines[i]); // If text requires an icon, add size to measure if (iconId >= 0) @@ -5234,7 +5611,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C // WARNING: If only icon provided, text could be pointing to EOF character: '\0' #if !defined(RAYGUI_NO_ICONS) - if ((lines[i] != NULL) && (lines[i][0] != '\0')) textSizeX += ICON_TEXT_PADDING; + if ((lines[i] != NULL) && (lines[i][0] != '\0')) textSizeX += RAYGUI_ICON_TEXT_PADDING; #endif } @@ -5271,12 +5648,11 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C { // NOTE: Considering icon height, probably different than text size GuiDrawIcon(iconId, (int)textBoundsPosition.x, (int)(textBounds.y + textBounds.height/2 - RAYGUI_ICON_SIZE*guiIconScale/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height)), guiIconScale, tint); - textBoundsPosition.x += (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); - textBoundsWidthOffset = (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); + textBoundsPosition.x += (float)(RAYGUI_ICON_SIZE*guiIconScale + RAYGUI_ICON_TEXT_PADDING); + textBoundsWidthOffset = (float)(RAYGUI_ICON_SIZE*guiIconScale + RAYGUI_ICON_TEXT_PADDING); } #endif - // Get size in bytes of text, - // considering end of line and line break + // Get size in bytes of text, considering end of line and line break int lineSize = 0; for (int c = 0; (lines[i][c] != '\0') && (lines[i][c] != '\n') && (lines[i][c] != '\r'); c++, lineSize++){ } float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize; @@ -5297,7 +5673,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C // NOTE: Normally, exiting the decoding sequence as soon as a bad byte is found (and return 0x3f) // but all of the bad bytes need to be drawn using the '?' symbol, moving one byte - if (codepoint == 0x3f) codepointSize = 1; // TODO: Review not recognized codepoints size + if (codepoint == 0x3f) codepointSize = 1; // WARNING: Not recognized codepoints size // Get glyph width to check if it goes out of bounds if (guiFont.glyphs[index].advanceX == 0) glyphWidth = ((float)guiFont.recs[index].width*scaleFactor); @@ -5313,7 +5689,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C textOffsetX = 0.0f; textOffsetY += (GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); - if (tempWrapCharMode) // Wrap at char level when too long words + if (tempWrapCharMode) // Wrap at char level when too long words { wrapMode = TEXT_WRAP_WORD; tempWrapCharMode = false; @@ -5344,12 +5720,12 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C } } - if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint + if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint else { - // TODO: There are multiple types of spaces in Unicode, + // WARNING: There are multiple types of spaces in Unicode, // maybe it's a good idea to add support for more: http://jkorpela.fi/chars/spaces.html - if ((codepoint != ' ') && (codepoint != '\t')) // Do not draw codepoints with no glyph + if ((codepoint != ' ') && (codepoint != '\t')) // Do not draw codepoints with no glyph { if (wrapMode == TEXT_WRAP_NONE) { @@ -5391,7 +5767,8 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C } if (wrapMode == TEXT_WRAP_NONE) posOffsetY += (float)(GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); - else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) posOffsetY += (textOffsetY + (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); + else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) + posOffsetY += (textOffsetY + GuiGetStyle(DEFAULT, TEXT_SIZE)); //--------------------------------------------------------------------------------- } @@ -5428,7 +5805,8 @@ static void GuiTooltip(Rectangle controlRec) { if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiControlExclusiveMode) { - Vector2 textSize = MeasureTextEx(GuiGetFont(), guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + Vector2 textSize = MeasureTextEx(guiFont, guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); if ((controlRec.x + textSize.x + 16) > GetScreenWidth()) controlRec.x -= (textSize.x + 16 - controlRec.width); @@ -5450,9 +5828,264 @@ static void GuiTooltip(Rectangle controlRec) } } +// Scroll bar control (used by GuiScrollPanel()) +static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) +{ + GuiState state = guiState; + + // Is the scrollbar horizontal or vertical? + bool isVertical = (bounds.width > bounds.height)? false : true; + + // The size (width or height depending on scrollbar type) of the spinner buttons + const int spinnerSize = GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)? + (isVertical? (int)bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) : + (int)bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0; + + // Arrow buttons [<] [>] [∧] [∨] + Rectangle arrowUpLeft = { 0 }; + Rectangle arrowDownRight = { 0 }; + + // Actual area of the scrollbar excluding the arrow buttons + Rectangle scrollbar = { 0 }; + + // Slider bar that moves --[///]----- + Rectangle slider = { 0 }; + + // Normalize value + if (value > maxValue) value = maxValue; + if (value < minValue) value = minValue; + + int valueRange = maxValue - minValue; + if (valueRange <= 0) valueRange = 1; + + int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); + if (sliderSize < 1) sliderSize = 1; // Consider a minimum slider size of 1 pixel + + // Calculate rectangles for all of the components + arrowUpLeft = RAYGUI_CLITERAL(Rectangle){ + (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), + (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), + (float)spinnerSize, (float)spinnerSize }; + + if (isVertical) + { + arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + bounds.height - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; + scrollbar = RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), arrowUpLeft.y + arrowUpLeft.height, bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)), bounds.height - arrowUpLeft.height - arrowDownRight.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) }; + + // Make sure the slider won't get outside of the scrollbar + sliderSize = (sliderSize >= scrollbar.height)? ((int)scrollbar.height - 2) : sliderSize; + slider = RAYGUI_CLITERAL(Rectangle){ + bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), + scrollbar.y + (int)(((float)(value - minValue)/valueRange)*(scrollbar.height - sliderSize)), + bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)), + (float)sliderSize }; + } + else // horizontal + { + arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; + scrollbar = RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x + arrowUpLeft.width, bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), bounds.width - arrowUpLeft.width - arrowDownRight.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)) }; + + // Make sure the slider won't get outside of the scrollbar + sliderSize = (sliderSize >= scrollbar.width)? ((int)scrollbar.width - 2) : sliderSize; + slider = RAYGUI_CLITERAL(Rectangle){ + scrollbar.x + (int)(((float)(value - minValue)/valueRange)*(scrollbar.width - sliderSize)), + bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), + (float)sliderSize, + bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)) }; + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (GUI_BUTTON_DOWN && + !CheckCollisionPointRec(mousePoint, arrowUpLeft) && + !CheckCollisionPointRec(mousePoint, arrowDownRight)) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + state = STATE_PRESSED; + + if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); + else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + + // Handle mouse wheel + float scrollDelta = GUI_SCROLL_DELTA; + if (scrollDelta != 0) value += (int)scrollDelta; + + // Handle mouse button down + if (GUI_BUTTON_PRESSED) + { + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + + // Check arrows click + if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + else if (!CheckCollisionPointRec(mousePoint, slider)) + { + // If click on scrollbar position but not on slider, place slider directly on that position + if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); + else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); + } + + state = STATE_PRESSED; + } + + // Keyboard control on mouse hover scrollbar + /* + if (isVertical) + { + if (GUI_KEY_DOWN(KEY_DOWN)) value += 5; + else if (GUI_KEY_DOWN(KEY_UP)) value -= 5; + } + else + { + if (GUI_KEY_DOWN(KEY_RIGHT)) value += 5; + else if (GUI_KEY_DOWN(KEY_LEFT)) value -= 5; + } + */ + } + + // Normalize value + if (value > maxValue) value = maxValue; + if (value < minValue) value = minValue; + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED))); // Draw the background + + GuiDrawRectangle(scrollbar, 0, BLANK, GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL))); // Draw the scrollbar active area background + GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BORDER + state*3))); // Draw the slider bar + + // Draw arrows (using icon if available) + if (GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)) + { +#if defined(RAYGUI_NO_ICONS) + GuiDrawText(isVertical? "^" : "<", + RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); + GuiDrawText(isVertical? "v" : ">", + RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); +#else + GuiDrawText(isVertical? GuiIconText(ICON_ARROW_UP_FILL, NULL) : GuiIconText(ICON_ARROW_LEFT_FILL, NULL), + RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_UP_FILL / ICON_ARROW_LEFT_FILL + GuiDrawText(isVertical? GuiIconText(ICON_ARROW_DOWN_FILL, NULL) : GuiIconText(ICON_ARROW_RIGHT_FILL, NULL), + RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_DOWN_FILL / ICON_ARROW_RIGHT_FILL +#endif + } + //-------------------------------------------------------------------- + + return value; +} + +// Update font image atlas to append raygui icons +static int GuiFontIconBaking(Image *imFont, Font font, Rectangle *whiteRec) +{ + int iconOffsetY = 0; + + // Check max glyph rec y bottom position in the atlas image, + // to start drawing icons below that line + int maxGlyphRecY = 0; + for (int i = 0; i < font.glyphCount; i++) + { + if ((font.recs[i].y + font.recs[i].height) > maxGlyphRecY) + maxGlyphRecY = (int)font.recs[i].y + (int)font.recs[i].height; + } + + int maxIconsPerLine = imFont->width/(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + int reqIconLines = RAYGUI_ICON_MAX_FONT_BACKED/maxIconsPerLine + RAYGUI_ICON_MAX_FONT_BACKED%maxIconsPerLine + 1; // One extra line + int reqHeight = reqIconLines*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + + // Check if image requires scaling and how much + if ((maxGlyphRecY + reqHeight) > imFont->height) + { + int newImHeight = 1; + while (newImHeight < (maxGlyphRecY + reqHeight)) newImHeight <<= 1; // Round to next POT + + char *newImData = (char *)RL_CALLOC(imFont->width*newImHeight*2, sizeof(char)); + memcpy(newImData, imFont->data, imFont->width*imFont->height*2); + RL_FREE(imFont->data); + + // Clear imFont bottom-right corner rec + for (int y = 0; y < 4; y++) + for (int x = 0; x < 4; x++) + ((unsigned short *)newImData)[(imFont->height - y - 1)*imFont->width + imFont->width - x - 1] = 0x0000; + + imFont->data = newImData; + imFont->height = newImHeight; + + // Set new image white corner and new white rec + for (int y = 0; y < 3; y++) + for (int x = 0; x < 3; x++) + ((unsigned short *)newImData)[(imFont->height - y - 1)*imFont->width + imFont->width - x - 1] = 0xffff; + + *whiteRec = RAYGUI_CLITERAL(Rectangle){ (float)imFont->width - 2, (float)imFont->height - 2, 1, 1 }; + } + + // Calculate image offset positions to start drawing + // NOTE: For Y, look for a multiple of icon size + 2*padding, for better alignment + int offsetX = RAYGUI_ICON_FONT_ATLAS_PADDING; + int offsetY = ((maxGlyphRecY + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING - 1))/ + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING))*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + + RAYGUI_ICON_FONT_ATLAS_PADDING; + + iconOffsetY = offsetY - RAYGUI_ICON_FONT_ATLAS_PADDING; + unsigned short *pixels = (unsigned short *)imFont->data; + + #define BIT_CHECK(a,b) ((a) & (1u<<(b))) + + for (int iconId = 0; iconId < RAYGUI_ICON_MAX_FONT_BACKED; iconId++) + { + // Wrap to next line if next icon won't fit + if ((offsetX + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING)) > imFont->width) + { + offsetX = RAYGUI_ICON_FONT_ATLAS_PADDING; + offsetY += RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING; + } + + for (int i = 0, y = 0; i < RAYGUI_ICON_DATA_ELEMENTS; i++) + { + unsigned int data = guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i]; + + for (int k = 0; k < 32; k++) + { + pixels[(offsetY + y)*imFont->width + offsetX + k%16] = (BIT_CHECK(data, k))? 0xffff : 0x00ff; + + if ((k == 15) || (k == 31)) y++; + } + } + + // Update current icon X position + offsetX += (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + } + + return iconOffsetY; +} + // Split controls text into multiple strings -// Also check for multiple columns (required by GuiToggleGroup()) -static char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow) +// NOTE: Re-used by GuiToggleSlider(), GuiComboBox(), GuiDropdownBox(), GuiListView(), GuiMessageBox(), GuiInputBox() +static char **GuiTextSplit(const char *text, char delimiter, int *count) { // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, @@ -5461,24 +6094,19 @@ static char **GuiTextSplit(const char *text, char delimiter, int *count, int *te // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE // NOTE: Those definitions could be externally provided if required - // TODO: HACK: GuiTextSplit() - Review how textRows are returned to user - // textRow is an externally provided array of integers that stores row number for every splitted string - #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS) #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128 #endif #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE) - #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 + #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 // WARNING: Max expected size for all concat items #endif - static char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL }; // String pointers array (points to buffer data) + static char *itemPtrs[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { 0 }; // String pointers array (points to buffer data) static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; // Buffer data (text input copy with '\0' added) memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE); - result[0] = buffer; - int counter = 1; - - if (textRow != NULL) textRow[0] = 0; + itemPtrs[0] = buffer; + int itemCounter = 1; // Count how many substrings text contains and point to every one of them for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++) @@ -5487,24 +6115,16 @@ static char **GuiTextSplit(const char *text, char delimiter, int *count, int *te if (buffer[i] == '\0') break; else if ((buffer[i] == delimiter) || (buffer[i] == '\n')) { - result[counter] = buffer + i + 1; + itemPtrs[itemCounter] = buffer + i + 1; + buffer[i] = '\0'; // Set terminator for current item - if (textRow != NULL) - { - if (buffer[i] == '\n') textRow[counter] = textRow[counter - 1] + 1; - else textRow[counter] = textRow[counter - 1]; - } - - buffer[i] = '\0'; // Set an end of string at this point - - counter++; - if (counter >= RAYGUI_TEXTSPLIT_MAX_ITEMS) break; + itemCounter++; + if (itemCounter >= RAYGUI_TEXTSPLIT_MAX_ITEMS) break; } } - *count = counter; - - return result; + *count = itemCounter; + return itemPtrs; } // Convert color data from RGB to HSV @@ -5631,179 +6251,9 @@ static Vector3 ConvertHSVtoRGB(Vector3 hsv) return rgb; } -// Scroll bar control (used by GuiScrollPanel()) -static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) -{ - GuiState state = guiState; - - // Is the scrollbar horizontal or vertical? - bool isVertical = (bounds.width > bounds.height)? false : true; - - // The size (width or height depending on scrollbar type) of the spinner buttons - const int spinnerSize = GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)? - (isVertical? (int)bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) : - (int)bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0; - - // Arrow buttons [<] [>] [∧] [∨] - Rectangle arrowUpLeft = { 0 }; - Rectangle arrowDownRight = { 0 }; - - // Actual area of the scrollbar excluding the arrow buttons - Rectangle scrollbar = { 0 }; - - // Slider bar that moves --[///]----- - Rectangle slider = { 0 }; - - // Normalize value - if (value > maxValue) value = maxValue; - if (value < minValue) value = minValue; - - int valueRange = maxValue - minValue; - if (valueRange <= 0) valueRange = 1; - - int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); - if (sliderSize < 1) sliderSize = 1; // TODO: Consider a minimum slider size - - // Calculate rectangles for all of the components - arrowUpLeft = RAYGUI_CLITERAL(Rectangle){ - (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), - (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), - (float)spinnerSize, (float)spinnerSize }; - - if (isVertical) - { - arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + bounds.height - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; - scrollbar = RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), arrowUpLeft.y + arrowUpLeft.height, bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)), bounds.height - arrowUpLeft.height - arrowDownRight.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) }; - - // Make sure the slider won't get outside of the scrollbar - sliderSize = (sliderSize >= scrollbar.height)? ((int)scrollbar.height - 2) : sliderSize; - slider = RAYGUI_CLITERAL(Rectangle){ - bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), - scrollbar.y + (int)(((float)(value - minValue)/valueRange)*(scrollbar.height - sliderSize)), - bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)), - (float)sliderSize }; - } - else // horizontal - { - arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; - scrollbar = RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x + arrowUpLeft.width, bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), bounds.width - arrowUpLeft.width - arrowDownRight.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)) }; - - // Make sure the slider won't get outside of the scrollbar - sliderSize = (sliderSize >= scrollbar.width)? ((int)scrollbar.width - 2) : sliderSize; - slider = RAYGUI_CLITERAL(Rectangle){ - scrollbar.x + (int)(((float)(value - minValue)/valueRange)*(scrollbar.width - sliderSize)), - bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), - (float)sliderSize, - bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)) }; - } - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GUI_POINTER_POSITION; - - if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds - { - if (GUI_BUTTON_DOWN && - !CheckCollisionPointRec(mousePoint, arrowUpLeft) && - !CheckCollisionPointRec(mousePoint, arrowDownRight)) - { - if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) - { - state = STATE_PRESSED; - - if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); - else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); - } - } - else - { - guiControlExclusiveMode = false; - guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; - } - } - else if (CheckCollisionPointRec(mousePoint, bounds)) - { - state = STATE_FOCUSED; - - // Handle mouse wheel - float scrollDelta = GUI_SCROLL_DELTA; - if (scrollDelta != 0) value += (int)scrollDelta; - - // Handle mouse button down - if (GUI_BUTTON_PRESSED) - { - guiControlExclusiveMode = true; - guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts - - // Check arrows click - if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - else if (!CheckCollisionPointRec(mousePoint, slider)) - { - // If click on scrollbar position but not on slider, place slider directly on that position - if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); - else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); - } - - state = STATE_PRESSED; - } - - // Keyboard control on mouse hover scrollbar - /* - if (isVertical) - { - if (GUI_KEY_DOWN(KEY_DOWN)) value += 5; - else if (GUI_KEY_DOWN(KEY_UP)) value -= 5; - } - else - { - if (GUI_KEY_DOWN(KEY_RIGHT)) value += 5; - else if (GUI_KEY_DOWN(KEY_LEFT)) value -= 5; - } - */ - } - - // Normalize value - if (value > maxValue) value = maxValue; - if (value < minValue) value = minValue; - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED))); // Draw the background - - GuiDrawRectangle(scrollbar, 0, BLANK, GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL))); // Draw the scrollbar active area background - GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BORDER + state*3))); // Draw the slider bar - - // Draw arrows (using icon if available) - if (GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)) - { -#if defined(RAYGUI_NO_ICONS) - GuiDrawText(isVertical? "^" : "<", - RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); - GuiDrawText(isVertical? "v" : ">", - RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); -#else - GuiDrawText(isVertical? "#121#" : "#118#", - RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_UP_FILL / ICON_ARROW_LEFT_FILL - GuiDrawText(isVertical? "#120#" : "#119#", - RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_DOWN_FILL / ICON_ARROW_RIGHT_FILL -#endif - } - //-------------------------------------------------------------------- - - return value; -} - // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f -// WARNING: It multiplies current alpha by alpha scale factor +// WARNING: It multiplies current alpha by alpha scale factor, +// raylib Fade() multiplies alpha by 255.0f static Color GuiFade(Color color, float alpha) { if (alpha < 0.0f) alpha = 0.0f; @@ -5828,6 +6278,19 @@ static Color GetColor(int hexValue) return color; } +// Get color with alpha applied, alpha goes from 0.0f to 1.0f +static Color Fade(Color color, float alpha) +{ + Color result = color; + + if (alpha < 0.0f) alpha = 0.0f; + else if (alpha > 1.0f) alpha = 1.0f; + + result.a = (unsigned char)(255.0f*alpha); + + return result; +} + // Returns hexadecimal value for a Color static int ColorToInt(Color color) { @@ -5852,7 +6315,8 @@ static const char *TextFormat(const char *text, ...) #define RAYGUI_TEXTFORMAT_MAX_SIZE 256 #endif - static char buffer[RAYGUI_TEXTFORMAT_MAX_SIZE]; + static char buffer[RAYGUI_TEXTFORMAT_MAX_SIZE] = { 0 }; + memset(buffer, 0, RAYGUI_TEXTFORMAT_MAX_SIZE); va_list args; va_start(args, text); @@ -5862,61 +6326,6 @@ static const char *TextFormat(const char *text, ...) return buffer; } -// Draw rectangle with vertical gradient fill color -// NOTE: This function is only used by GuiColorPicker() -static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2) -{ - Rectangle bounds = { (float)posX, (float)posY, (float)width, (float)height }; - DrawRectangleGradientEx(bounds, color1, color2, color2, color1); -} - -// Split string into multiple strings -char **TextSplit(const char *text, char delimiter, int *count) -{ - // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) - // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, - // all used memory is static... it has some limitations: - // 1. Maximum number of possible split strings is set by RAYGUI_TEXTSPLIT_MAX_ITEMS - // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE - - #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS) - #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128 - #endif - #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE) - #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 - #endif - - static const char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL }; - static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; - memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE); - - result[0] = buffer; - int counter = 0; - - if (text != NULL) - { - counter = 1; - - // Count how many substrings text contains and point to every one of them - for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++) - { - buffer[i] = text[i]; - if (buffer[i] == '\0') break; - else if (buffer[i] == delimiter) - { - buffer[i] = '\0'; // Set an end of string at this point - result[counter] = buffer + i + 1; - counter++; - - if (counter == RAYGUI_TEXTSPLIT_MAX_ITEMS) break; - } - } - } - - *count = counter; - return result; -} - // Get integer value from text // NOTE: This function replaces atoi() [stdlib.h] static int TextToInteger(const char *text) diff --git a/examples/shapes/raygui.h b/examples/shapes/raygui.h index 07ef3c05b..f7a116150 100644 --- a/examples/shapes/raygui.h +++ b/examples/shapes/raygui.h @@ -1,6 +1,6 @@ /******************************************************************************************* * -* raygui v5.0-dev - A simple and easy-to-use immediate-mode gui library +* raygui v5.0 - A simple and easy-to-use immediate-mode gui library * * DESCRIPTION: * raygui is a tools-dev-focused immediate-mode-gui library based on raylib but also @@ -37,7 +37,7 @@ * - Line * - Panel --> StatusBar * - ScrollPanel --> StatusBar -* - TabBar --> Button +* - TabBar --> Toggle, Button * * # Basic Controls * - Label @@ -134,6 +134,10 @@ * Includes custom ricons.h header defining a set of custom icons, * this file can be generated using rGuiIcons tool * +* #define RAYGUI_FONT_ICONS_BAKING +* On gui font loading from style file, append the icons to font atlas image, so, +* icons can be drawn along the text as a texture, instead of using shapes to draw them +* * #define RAYGUI_DEBUG_RECS_BOUNDS * Draw control bounds rectangles for debug * @@ -141,16 +145,26 @@ * Draw text bounds rectangles for debug * * VERSIONS HISTORY: -* 5.0 (xx-Mar-2026) ADDED: Support up to 32 controls (v500) +* 5.0 (20-Jul-2026) ADDED: NEW control: GuiTabBar() +* ADDED: Support up to 512 icons (v500) +* ADDED: Support icons baking into font atlas image * ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes -* ADDED: GuiValueBoxFloat() +* ADDED: GuiValueBoxFloat(), with floats support * ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP * ADDED: GuiListView() property: LIST_ITEMS_BORDER_WIDTH -* ADDED: GuiLoadIconsFromMemory() -* ADDED: Multiple new icons +* ADDED: GuiLoadIconsFromMemory(), used by GuiLoadIcons() * ADDED: Macros for inputs customization, raylib decoupling +* ADDED: Control result return values: 1-RESULT_PRESSED, 2-RESULT_CHANGED, >2-Control_custom * REMOVED: GuiSpinner() from controls list, using BUTTON + VALUEBOX properties * REMOVED: GuiSliderPro(), functionality was redundant +* REMOVED: TextSplit() raylib function requirement on RAYGUI_STANDALONE +* REDESIGNED: WARNING: GuiLoadStyleFromMemory() to support icons baking into font atlas +* REDESIGNED: GuiToggleGroup() to process rows/cols with no need for GuiTextSplit() +* REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion +* REDESIGNED: WARNING: TEXT_LINE_SPACING does not consider text height, only lines spacing +* REDESIGNED: WARNING: GuiMessageBox(), added parameter for btn return, unify result +* REDESIGNED: WARNING: GuiTextInputBox(), added parameter for btn return, unify result +* REVIEWED: GuiLoadIconsFromMemory(), fixed memory issues * REVIEWED: Controls using text labels to use LABEL properties * REVIEWED: Replaced sprintf() by snprintf() for more safety * REVIEWED: GuiTabBar(), close tab with mouse middle button @@ -165,8 +179,6 @@ * REVIEWED: GuiProgressBar(), improved borders computing * REVIEWED: GuiTextBox(), multiple improvements: autocursor and more * REVIEWED: Functions descriptions, removed wrong return value reference -* REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion -* REDESIGNED: WARNING: TEXT_LINE_SPACING does not consider text height, only lines spacing * * 4.0 (12-Sep-2023) ADDED: GuiToggleSlider() * ADDED: GuiColorPickerHSV() and GuiColorPanelHSV() @@ -273,7 +285,7 @@ * 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria * * DEPENDENCIES: -* raylib 5.6-dev - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing +* raylib 6.1-dev - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing * * STANDALONE MODE: * By default raygui depends on raylib mostly for the inputs and the drawing functionality but that dependency can be disabled @@ -340,10 +352,10 @@ #ifndef RAYGUI_H #define RAYGUI_H -#define RAYGUI_VERSION_MAJOR 4 -#define RAYGUI_VERSION_MINOR 5 +#define RAYGUI_VERSION_MAJOR 5 +#define RAYGUI_VERSION_MINOR 0 #define RAYGUI_VERSION_PATCH 0 -#define RAYGUI_VERSION "5.0-dev" +#define RAYGUI_VERSION "5.0" #if !defined(RAYGUI_STANDALONE) #include "raylib.h" @@ -357,9 +369,13 @@ #elif defined(USE_LIBTYPE_SHARED) #define RAYGUIAPI __declspec(dllimport) // Using the library as a Win32 shared library (.dll) #endif -#if !defined(_CRT_SECURE_NO_WARNINGS) -#define _CRT_SECURE_NO_WARNINGS // Disable unsafe warnings on scanf() functions in MSVC -#endif + #if !defined(_CRT_SECURE_NO_WARNINGS) + #define _CRT_SECURE_NO_WARNINGS // Disable unsafe warnings on scanf() functions in MSVC + #endif +#else + #if defined(BUILD_LIBTYPE_SHARED) + #define RAYGUIAPI __attribute__((visibility("default"))) // Building as a Unix shared library (.so/.dylib) + #endif #endif // Function specifiers definition @@ -379,8 +395,8 @@ #define RAYGUI_LOG(...) #endif +#if !defined(RAYGUI_STANDALONE) // Macros to define required UI inputs, including mapping to gamepad controls -// TODO: Define additionally required macros for missing inputs #if !defined(GUI_BUTTON_DOWN) #define GUI_BUTTON_DOWN (IsMouseButtonDown(MOUSE_LEFT_BUTTON) || IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) #endif @@ -391,13 +407,15 @@ #if !defined(GUI_BUTTON_PRESSED) #define GUI_BUTTON_PRESSED (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsGamepadButtonPressed(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) #endif -// TODO: WARNING: GuiTabBar() still requires IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON) +#if !defined(GUI_BUTTON_PRESSED_MID) + #define GUI_BUTTON_PRESSED_MID (IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON) || IsGamepadButtonPressed(0, GAMEPAD_BUTTON_RIGHT_FACE_UP)) +#endif #if !defined(GUI_BUTTON_RELEASED) #define GUI_BUTTON_RELEASED (IsMouseButtonReleased(MOUSE_LEFT_BUTTON) || IsGamepadButtonReleased(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) #endif #if !defined(GUI_SCROLL_DELTA) // Mapping to scroll delta changes - // TODO: Review inconsistencies between platforms + // TODO: Review mouse scroll inconsistencies between platforms #if defined(PLATFORM_WEB) // NOTE: Gamepad axis triggers not detected on web platform #define GUI_SCROLL_DELTA ((float)IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_TRIGGER_2) - (float)IsGamepadButtonDown(0, GAMEPAD_BUTTON_LEFT_TRIGGER_2)) @@ -417,6 +435,18 @@ #if !defined(GUI_INPUT_KEY) #define GUI_INPUT_KEY GetCharPressed() #endif +#else + #define GUI_BUTTON_DOWN 0 + #define GUI_BUTTON_DOWN_ALT 0 + #define GUI_BUTTON_PRESSED 0 + #define GUI_BUTTON_PRESSED_MID 0 + #define GUI_BUTTON_RELEASED 0 + #define GUI_SCROLL_DELTA 0 + #define GUI_POINTER_POSITION (Vector2){ 0 } + #define GUI_KEY_DOWN(key) 0 + #define GUI_KEY_PRESSED(key) 0 + #define GUI_INPUT_KEY 0 +#endif //---------------------------------------------------------------------------------- // Types and Structures Definition @@ -451,6 +481,8 @@ unsigned char a; } Color; +#define BLANK (Color){ 0, 0, 0, 0 } // Blank (Transparent) + // Rectangle type typedef struct Rectangle { float x; @@ -459,7 +491,7 @@ float height; } Rectangle; - // TODO: Texture2D type is very coupled to raylib, required by Font type + // NOTE: Texture2D type is very coupled to raylib, required by Font type // It should be redesigned to be provided by user typedef struct Texture { unsigned int id; // OpenGL texture id @@ -490,7 +522,7 @@ Image image; // Character image data } GlyphInfo; - // TODO: Font type is very coupled to raylib, mostly required by GuiLoadStyle() + // NOTE: Font type is very coupled to raylib, mostly required by GuiLoadStyle() // It should be redesigned to be provided by user typedef struct Font { int baseSize; // Base size (default chars height) @@ -523,6 +555,15 @@ typedef struct GuiTextStyle { } GuiTextStyle; */ +// Gui control result +typedef enum { + RESULT_NONE = 0, + RESULT_PRESSED = 1, + RESULT_CHANGED = 2, + + RESULT_TAB_CLOSE = 4 // GuiTabBar(), tab close request +} GuiResult; + // Gui control state typedef enum { STATE_NORMAL = 0, @@ -555,88 +596,95 @@ typedef enum { } GuiTextWrapMode; // Gui controls +// NOTE: Up to 16 controls supported or 32 controls (v500) typedef enum { // Default -> populates to all controls when set - DEFAULT = 0, + DEFAULT = 0, // Basic controls - LABEL, // Used also for: LABELBUTTON - BUTTON, - TOGGLE, // Used also for: TOGGLEGROUP - SLIDER, // Used also for: SLIDERBAR, TOGGLESLIDER - PROGRESSBAR, - CHECKBOX, - COMBOBOX, - DROPDOWNBOX, - TEXTBOX, // Used also for: TEXTBOXMULTI - VALUEBOX, - CONTROL11, - LISTVIEW, - COLORPICKER, - SCROLLBAR, - STATUSBAR + LABEL = 1, // Used also for: LABELBUTTON + BUTTON = 2, + TOGGLE = 3, // Used also for: TOGGLEGROUP + SLIDER = 4, // Used also for: SLIDERBAR, TOGGLESLIDER + PROGRESSBAR = 5, + CHECKBOX = 6, + COMBOBOX = 7, + DROPDOWNBOX = 8, + TEXTBOX = 9, // Used also for: TEXTBOXMULTI + VALUEBOX = 10, + TABBAR = 11, + LISTVIEW = 12, + COLORPICKER = 13, + SCROLLBAR = 14, + STATUSBAR = 15 + // NOTE: More controls can be added if required } GuiControl; -// Gui base properties for every control -// NOTE: RAYGUI_MAX_PROPS_BASE properties (by default 16 properties) +// Controls BASE properties for every control (RAYGUI_MAX_PROPS_BASE = 16) +// NOTE: Properties required for all controls, DEFAULT control sets +// default values for them but they can be overriden per control typedef enum { - BORDER_COLOR_NORMAL = 0, // Control border color in STATE_NORMAL - BASE_COLOR_NORMAL, // Control base color in STATE_NORMAL - TEXT_COLOR_NORMAL, // Control text color in STATE_NORMAL - BORDER_COLOR_FOCUSED, // Control border color in STATE_FOCUSED - BASE_COLOR_FOCUSED, // Control base color in STATE_FOCUSED - TEXT_COLOR_FOCUSED, // Control text color in STATE_FOCUSED - BORDER_COLOR_PRESSED, // Control border color in STATE_PRESSED - BASE_COLOR_PRESSED, // Control base color in STATE_PRESSED - TEXT_COLOR_PRESSED, // Control text color in STATE_PRESSED - BORDER_COLOR_DISABLED, // Control border color in STATE_DISABLED - BASE_COLOR_DISABLED, // Control base color in STATE_DISABLED - TEXT_COLOR_DISABLED, // Control text color in STATE_DISABLED - BORDER_WIDTH = 12, // Control border size, 0 for no border - //TEXT_SIZE, // Control text size (glyphs max height) -> GLOBAL for all controls - //TEXT_SPACING, // Control text spacing between glyphs -> GLOBAL for all controls - //TEXT_LINE_SPACING, // Control text spacing between lines -> GLOBAL for all controls - TEXT_PADDING = 13, // Control text padding, not considering border - TEXT_ALIGNMENT = 14, // Control text horizontal alignment inside control text bound (after border and padding) - //TEXT_WRAP_MODE // Control text wrap-mode inside text bounds -> GLOBAL for all controls + BORDER_COLOR_NORMAL = 0, // Control border color in STATE_NORMAL + BASE_COLOR_NORMAL = 1, // Control base color in STATE_NORMAL + TEXT_COLOR_NORMAL = 2, // Control text color in STATE_NORMAL + BORDER_COLOR_FOCUSED = 3, // Control border color in STATE_FOCUSED + BASE_COLOR_FOCUSED = 4, // Control base color in STATE_FOCUSED + TEXT_COLOR_FOCUSED = 5, // Control text color in STATE_FOCUSED + BORDER_COLOR_PRESSED = 6, // Control border color in STATE_PRESSED + BASE_COLOR_PRESSED = 7, // Control base color in STATE_PRESSED + TEXT_COLOR_PRESSED = 8, // Control text color in STATE_PRESSED + BORDER_COLOR_DISABLED = 9, // Control border color in STATE_DISABLED + BASE_COLOR_DISABLED = 10, // Control base color in STATE_DISABLED + TEXT_COLOR_DISABLED = 11, // Control text color in STATE_DISABLED + BORDER_WIDTH = 12, // Control border size, 0 for no border + TEXT_PADDING = 13, // Control text padding, not considering border + TEXT_ALIGNMENT = 14, // Control text horizontal alignment inside control text bound (after border and padding): 0-Left, 1-Center, 2-Right + BASEPROP16 = 15 // Not used yet... } GuiControlProperty; -// TODO: Which text styling properties should be global or per-control? -// At this moment TEXT_PADDING and TEXT_ALIGNMENT is configured and saved per control while -// TEXT_SIZE, TEXT_SPACING, TEXT_LINE_SPACING, TEXT_ALIGNMENT_VERTICAL, TEXT_WRAP_MODE are global and -// should be configured by user as needed while defining the UI layout -// Gui extended properties depend on control -// NOTE: RAYGUI_MAX_PROPS_EXTENDED properties (by default, max 8 properties) +// WARNING: Some properties have been chosen to be global with DEFAULT - EXTENDED properties: +// - TEXT_SIZE, // Control text size (glyphs max height) +// - TEXT_SPACING, // Control text spacing between glyphs +// - TEXT_LINE_SPACING, // Control text spacing between lines +// - TEXT_WRAP_MODE // Control text wrap-mode inside text bounds +// +// While other properties can be setup per globally (DEFAULT) or per control: +// - TEXT_PADDING // Control text padding, not considering border +// - TEXT_ALIGNMENT // Control text horizontal alignment inside control text bound + + +// Controls EXTENDED properties (RAYGUI_MAX_PROPS_EXTENDED = 8) +// WARNING: Only 8 slots vailable for those properties per control, including DEFAULT //---------------------------------------------------------------------------------- -// DEFAULT extended properties -// NOTE: Those properties are common to all controls or global -// WARNING: Only 8 slots vailable for those properties by default +// DEFAULT control, extended properties +// NOTE: Those properties are global for all controls, they can not be setup per control typedef enum { - TEXT_SIZE = 16, // Text size (glyphs max height) - TEXT_SPACING, // Text spacing between glyphs - LINE_COLOR, // Line control color - BACKGROUND_COLOR, // Background color - TEXT_LINE_SPACING, // Text spacing between lines - TEXT_ALIGNMENT_VERTICAL, // Text vertical alignment inside text bounds (after border and padding) - TEXT_WRAP_MODE // Text wrap-mode inside text bounds - //TEXT_DECORATION // Text decoration: 0-None, 1-Underline, 2-Line-through, 3-Overline - //TEXT_DECORATION_THICK // Text decoration line thickness + TEXT_SIZE = 16, // Text size (glyphs max height) + TEXT_SPACING = 17, // Text spacing between glyphs + LINE_COLOR = 18, // Line control color + BACKGROUND_COLOR = 19, // Background color + TEXT_LINE_SPACING = 20, // Text spacing between lines + TEXT_ALIGNMENT_VERTICAL = 21, // Text vertical alignment inside text bounds (after border and padding): 0-Top, 1-Middle, 2-Bottom + TEXT_WRAP_MODE = 22, // Text wrap-mode inside text bounds + EXTPROP08 = 23 // Not used yet... } GuiDefaultProperty; -// Other possible text properties: -// TEXT_WEIGHT // Normal, Italic, Bold -> Requires specific font change -// TEXT_INDENT // Text indentation -> Now using TEXT_PADDING... +// Other possible text extended properties: +// TEXT_DECORATION // Text decoration: 0-None, 1-Underline, 2-Line-through, 3-Overline +// TEXT_DECORATION_THICK // Text decoration line thickness +// TEXT_FONT_WEIGHT // Text font weight: 0-Normal, 1-Bold, 2-Italic -> Requires specific font change // Label //typedef enum { } GuiLabelProperty; -// Button/Spinner +// Button //typedef enum { } GuiButtonProperty; // Toggle/ToggleGroup typedef enum { GROUP_PADDING = 16, // ToggleGroup separation between toggles + GROUP_WIDTH_FULL // ToggleGroup bounds width considers all items: 0-Width per item, 1-Full width } GuiToggleProperty; // Slider/SliderBar @@ -648,7 +696,7 @@ typedef enum { // ProgressBar typedef enum { PROGRESS_PADDING = 16, // ProgressBar internal padding - PROGRESS_SIDE, // ProgressBar increment side: 0-left->right, 1-right-left + PROGRESS_SIDE, // ProgressBar increment side: 0-Left->Right, 1-Right->Left } GuiProgressBarProperty; // ScrollBar @@ -677,12 +725,12 @@ typedef enum { ARROW_PADDING = 16, // DropdownBox arrow separation from border and items DROPDOWN_ITEMS_SPACING, // DropdownBox items separation DROPDOWN_ARROW_HIDDEN, // DropdownBox arrow hidden - DROPDOWN_ROLL_UP // DropdownBox roll up flag (default rolls down) + DROPDOWN_ROLL_UP // DropdownBox roll up flag: 0-Roll down, 1-Roll up } GuiDropdownBoxProperty; // TextBox/TextBoxMulti/ValueBox/Spinner typedef enum { - TEXT_READONLY = 16, // TextBox in read-only mode: 0-text editable, 1-text no-editable + TEXT_READONLY = 16, // TextBox in read-only mode: 0-Text editable, 1-Text read-only } GuiTextBoxProperty; // ValueBox/Spinner @@ -691,31 +739,35 @@ typedef enum { SPINNER_BUTTON_SPACING, // Spinner buttons separation } GuiValueBoxProperty; -// Control11 -//typedef enum { } GuiControl11Property; +// TabBar +typedef enum { + TAB_ITEMS_WIDTH = 16, // TabBar tab items width + TAB_CLOSE_BUTTON, // TabBar tab close button: 0-Not shown, 1-Shown + TAB_LINE_SIDE, // TabBar tabs side: 0-Bottom, 1-Top +} GuiTabBarProperty; // ListView +#define SCROLLBAR_LEFT_SIDE 0 +#define SCROLLBAR_RIGHT_SIDE 1 + typedef enum { LIST_ITEMS_HEIGHT = 16, // ListView items height LIST_ITEMS_SPACING, // ListView items separation SCROLLBAR_WIDTH, // ListView scrollbar size (usually width) - SCROLLBAR_SIDE, // ListView scrollbar side (0-SCROLLBAR_LEFT_SIDE, 1-SCROLLBAR_RIGHT_SIDE) + SCROLLBAR_SIDE, // ListView scrollbar side: 0-Left side, 1-Right Side LIST_ITEMS_BORDER_NORMAL, // ListView items border enabled in normal state LIST_ITEMS_BORDER_WIDTH // ListView items border width } GuiListViewProperty; // ColorPicker typedef enum { - COLOR_SELECTOR_SIZE = 16, + COLOR_SELECTOR_SIZE = 16, // ColorPicker selector square size HUEBAR_WIDTH, // ColorPicker right hue bar width HUEBAR_PADDING, // ColorPicker right hue bar separation from panel HUEBAR_SELECTOR_HEIGHT, // ColorPicker right hue bar selector height HUEBAR_SELECTOR_OVERFLOW // ColorPicker right hue bar selector overflow } GuiColorPickerProperty; -#define SCROLLBAR_LEFT_SIDE 0 -#define SCROLLBAR_RIGHT_SIDE 1 - //---------------------------------------------------------------------------------- // Global Variables Definition //---------------------------------------------------------------------------------- @@ -749,6 +801,7 @@ RAYGUIAPI int GuiGetStyle(int control, int property); // Get one style // Styles loading functions RAYGUIAPI void GuiLoadStyle(const char *fileName); // Load style file over global style variable (.rgs) +RAYGUIAPI void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only) RAYGUIAPI void GuiLoadStyleDefault(void); // Load style default over global style // Tooltips management functions @@ -762,6 +815,7 @@ RAYGUIAPI const char *GuiIconText(int iconId, const char *text); // Get text wit RAYGUIAPI void GuiSetIconScale(int scale); // Set default icon drawing size RAYGUIAPI unsigned int *GuiGetIcons(void); // Get raygui icons data pointer RAYGUIAPI char **GuiLoadIcons(const char *fileName, bool loadIconsName); // Load raygui icons file (.rgi) into internal icons data +RAYGUIAPI char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName); // Load raygui icons file (.rgi) from memory into internal icons data RAYGUIAPI void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color); // Draw icon using pixel size at specified position #endif @@ -775,7 +829,6 @@ RAYGUIAPI int GuiWindowBox(Rectangle bounds, const char *title); RAYGUIAPI int GuiGroupBox(Rectangle bounds, const char *text); // Group Box control with text name RAYGUIAPI int GuiLine(Rectangle bounds, const char *text); // Line separator control, could contain text RAYGUIAPI int GuiPanel(Rectangle bounds, const char *text); // Panel control, useful to group controls -RAYGUIAPI int GuiTabBar(Rectangle bounds, char **text, int count, int *active); // Tab Bar control, returns TAB to be closed or -1 RAYGUIAPI int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view); // Scroll Panel control // Basic controls set @@ -803,15 +856,17 @@ RAYGUIAPI int GuiGrid(Rectangle bounds, const char *text, float spacing, int sub // Advance controls set RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active); // List View control -RAYGUIAPI int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus); // List View with extended parameters -RAYGUIAPI int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons); // Message Box control, displays a message -RAYGUIAPI int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive); // Text Input Box control, ask for text, supports secret -RAYGUIAPI int GuiColorPicker(Rectangle bounds, const char *text, Color *color); // Color Picker control (multiple color controls) +RAYGUIAPI int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus); // List View control, using text entries list and returning focus entry +RAYGUIAPI int GuiTabBar(Rectangle bounds, const char *text, int *hscroll, int *active); // Tab Bar control +RAYGUIAPI int GuiTabBarEx(Rectangle bounds, char **text, int count, int *hscroll, int *active, int *focus); // Tab Bar control, using text entries list and returning focus entry +RAYGUIAPI int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *btnText, int *btnActive); // Message Box control, displays a message +RAYGUIAPI int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, char *text, int textSize, const char *btnText, int *btnActive, bool *secretViewActive); // Text Input Box control, ask for text, supports secret +RAYGUIAPI int GuiColorPicker(Rectangle bounds, const char *text, Color *color); // Color Picker control, includes Color bar controls RAYGUIAPI int GuiColorPanel(Rectangle bounds, const char *text, Color *color); // Color Panel control RAYGUIAPI int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha); // Color Bar Alpha control RAYGUIAPI int GuiColorBarHue(Rectangle bounds, const char *text, float *value); // Color Bar Hue control -RAYGUIAPI int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Picker control that avoids conversion to RGB on each call (multiple color controls) -RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control that updates Hue-Saturation-Value color value, used by GuiColorPickerHSV() +RAYGUIAPI int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Picker control, using Hue-Saturation-Value color data, includes Color bar controls +RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control, using Hue-Saturation-Value color data //---------------------------------------------------------------------------------------------------------- #if !defined(RAYGUI_NO_ICONS) @@ -1071,16 +1126,17 @@ typedef enum { ICON_CONE = 247, ICON_ELLIPSOID = 248, ICON_CAPSULE = 249, - ICON_250 = 250, - ICON_251 = 251, - ICON_252 = 252, - ICON_253 = 253, - ICON_254 = 254, - ICON_255 = 255 + ICON_FILETYPE_FONT = 250, + ICON_FILETYPE_3D = 251, + ICON_FILETYPE_CODE_XML = 252, + ICON_FILETYPE_CODE_C = 253, + ICON_FILETYPE_CODE_PYTHON = 254, + ICON_FILETYPE_CODE_JS = 255, + ICON_FILETYPE_ICON = 256, } GuiIconName; #endif -#endif +#endif // RAYGUI_NO_ICONS #if defined(__cplusplus) } // Prevents name mangling of functions @@ -1096,11 +1152,11 @@ typedef enum { #if defined(RAYGUI_IMPLEMENTATION) -#include // required for: isspace() [GuiTextBox()] #include // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()] #include // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy() #include // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()] #include // Required for: roundf() [GuiColorPicker()] +#include // Required for: isspace() [GuiTextBox()] // Allow custom memory allocators #if defined(RAYGUI_MALLOC) || defined(RAYGUI_CALLOC) || defined(RAYGUI_FREE) @@ -1129,9 +1185,11 @@ typedef enum { #if !defined(RAYGUI_NO_ICONS) && !defined(RAYGUI_CUSTOM_ICONS) // Embedded icons, no external file provided -#define RAYGUI_ICON_SIZE 16 // Size of icons in pixels (squared) -#define RAYGUI_ICON_MAX_ICONS 256 // Maximum number of icons -#define RAYGUI_ICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id +#define RAYGUI_ICON_SIZE 16 // Size of icons in pixels (squared) +#define RAYGUI_ICON_MAX_ICONS 512 // Maximum number of icons +#define RAYGUI_ICON_MAX_FONT_BACKED 257 // Maximum number of icons to back in font atlas +#define RAYGUI_ICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id +#define RAYGUI_ICON_FONT_ATLAS_PADDING 1 // Padding between backed icons in font atlas // Icons data is defined by bit array (every bit represents one pixel) // Those arrays are stored as unsigned int data arrays, so, @@ -1149,7 +1207,7 @@ typedef enum { // NOTE 2: A different icon set could be loaded over this array using GuiLoadIcons(), // but loaded icons set must be same RAYGUI_ICON_SIZE and no more than RAYGUI_ICON_MAX_ICONS // -// guiIcons size is by default: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 KB +// guiIcons size is by default: 512*(16*16/32) = 16384 bytes = 16 KB //---------------------------------------------------------------------------------- static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_NONE @@ -1402,18 +1460,20 @@ static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = 0x00800000, 0x01400140, 0x02200220, 0x04100410, 0x08080808, 0x1c1c13e4, 0x08081004, 0x000007f0, // ICON_CONE 0x00000000, 0x07e00000, 0x20841918, 0x40824082, 0x40824082, 0x19182084, 0x000007e0, 0x00000000, // ICON_ELLIPSOID 0x00000000, 0x00000000, 0x20041ff8, 0x40024002, 0x40024002, 0x1ff82004, 0x00000000, 0x00000000, // ICON_CAPSULE - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_250 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_251 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_252 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_253 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_254 - 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_255 + 0x3ff00000, 0x201c2010, 0x21042004, 0x22842384, 0x264426c4, 0x2c242fe4, 0x20043e74, 0x00003ffc, // ICON_FILETYPE_FONT + 0x3ff00000, 0x201c2010, 0x20042004, 0x27742004, 0x29742944, 0x27742944, 0x20042004, 0x00003ffc, // ICON_FILETYPE_3D + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x24242244, 0x24242814, 0x20042244, 0x00003ffc, // ICON_FILETYPE_XML + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x21042f04, 0x21042104, 0x20042f04, 0x00003ffc, // ICON_FILETYPE_C + 0x3ff00000, 0x201c2010, 0x23842004, 0x2bf42a04, 0x2fd42814, 0x21c42054, 0x20042004, 0x00003ffc, // ICON_FILETYPE_PYTHON + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x22842ee4, 0x28a42e84, 0x20042e64, 0x00003ffc, // ICON_FILETYPE_JS + 0x3ff00000, 0x241c2010, 0x2a8c3104, 0x28242454, 0x2ed42004, 0x2a542a54, 0x20042ed4, 0x00003ffc, // ICON_FILETYPE_ICON + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_257 }; // NOTE: A pointer to current icons array should be defined static unsigned int *guiIconsPtr = guiIcons; -#endif // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS +#endif // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS #ifndef RAYGUI_ICON_SIZE #define RAYGUI_ICON_SIZE 0 @@ -1437,10 +1497,12 @@ typedef enum { BORDER = 0, BASE, TEXT, OTHER } GuiPropertyElement; static GuiState guiState = STATE_NORMAL; // Gui global state, if !STATE_NORMAL, forces defined state static Font guiFont = { 0 }; // Gui current font (WARNING: highly coupled to raylib) +static char guiFontName[32] = { 0 }; // Gui font filename, can be loaded from .rgs (Version: >=600) static bool guiLocked = false; // Gui lock state (no inputs processed) static float guiAlpha = 1.0f; // Gui controls transparency static unsigned int guiIconScale = 1; // Gui icon default scale (if icons enabled) +static unsigned int guiIconFontOffsetY = 0; // Gui icon font atlas offset (if icons backed) static bool guiTooltip = false; // Tooltip enabled/disabled static const char *guiTooltipPtr = NULL; // Tooltip string pointer (string provided by user) @@ -1521,22 +1583,22 @@ static int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle( static void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list static unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle() + +static Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font //------------------------------------------------------------------------------- // raylib functions already implemented in raygui //------------------------------------------------------------------------------- static Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value +static Color Fade(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f static int ColorToInt(Color color); // Returns hexadecimal value for a Color static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed' -static char **TextSplit(const char *text, char delimiter, int *count); // Split text into multiple strings static int TextToInteger(const char *text); // Get integer value from text static float TextToFloat(const char *text); // Get float value from text static int GetCodepointNext(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded text static const char *CodepointToUTF8(int codepoint, int *byteSize); // Encode codepoint into UTF-8 text (char array size returned as parameter) - -static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2); // Draw rectangle vertical gradient //------------------------------------------------------------------------------- #endif // RAYGUI_STANDALONE @@ -1544,22 +1606,22 @@ static void DrawRectangleGradientV(int posX, int posY, int width, int height, Co //---------------------------------------------------------------------------------- // Module Internal Functions Declaration //---------------------------------------------------------------------------------- -static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only) - +static int GetLineWidth(const char *text); // Get text line width (stops at '\n' or '\0') static Rectangle GetTextBounds(int control, Rectangle bounds); // Get text bounds considering control bounds static const char *GetTextIcon(const char *text, int *iconId); // Get text icon if provided and move text cursor -static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint); // Gui draw text using default font -static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // Gui draw rectangle using default raygui style +static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint); // Gui draw text using default font +static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // Gui draw rectangle using default raygui style -static char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow); // Split controls text into multiple strings +static char **GuiTextSplit(const char *text, char delimiter, int *count); // Split controls text into multiple strings static Vector3 ConvertHSVtoRGB(Vector3 hsv); // Convert color data from HSV to RGB static Vector3 ConvertRGBtoHSV(Vector3 rgb); // Convert color data from RGB to HSV -static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel() static void GuiTooltip(Rectangle controlRec); // Draw tooltip using control rec position +static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel() +static int GuiFontIconBaking(Image *imFont, Font font, Rectangle *whiteRec); // Update font image atlas to append raygui icons -static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor +static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor //---------------------------------------------------------------------------------- // Gui Setup Functions Definition @@ -1602,7 +1664,7 @@ void GuiSetFont(Font font) { if (font.texture.id > 0) { - // NOTE: If a font is tried to be set but default style has not been lazily loaded first, + // NOTE: If a font is tried to be set but default style has not been lazily loaded first, // it will be overwritten, so default style loading needs to be forced first if (!guiStyleLoaded) GuiLoadStyleDefault(); @@ -1653,7 +1715,7 @@ int GuiWindowBox(Rectangle bounds, const char *title) #define RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT 18 #endif - int result = 0; + int result = RESULT_NONE; //GuiState state = guiState; int statusBarHeight = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT; @@ -1675,11 +1737,15 @@ int GuiWindowBox(Rectangle bounds, const char *title) // Draw control //-------------------------------------------------------------------- GuiPanel(windowPanel, NULL); // Draw window base + + int tempTextAlignment = GuiGetStyle(STATUSBAR, TEXT_ALIGNMENT); + GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); GuiStatusBar(statusBar, title); // Draw window header as status bar + GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, tempTextAlignment); // Draw window close button int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); - int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); GuiSetStyle(BUTTON, BORDER_WIDTH, 1); GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); #if defined(RAYGUI_NO_ICONS) @@ -1691,7 +1757,7 @@ int GuiWindowBox(Rectangle bounds, const char *title) GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); //-------------------------------------------------------------------- - return result; // Window close button clicked: result = 1 + return result; } // Group Box control with text name @@ -1701,7 +1767,7 @@ int GuiGroupBox(Rectangle bounds, const char *text) #define RAYGUI_GROUPBOX_LINE_THICK 1 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Draw control @@ -1726,7 +1792,7 @@ int GuiLine(Rectangle bounds, const char *text) #define RAYGUI_LINE_TEXT_PADDING 4 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; Color color = GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)); @@ -1759,7 +1825,7 @@ int GuiPanel(Rectangle bounds, const char *text) #define RAYGUI_PANEL_BORDER_WIDTH 1 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Text will be drawn as a header bar (if provided) @@ -1775,7 +1841,7 @@ int GuiPanel(Rectangle bounds, const char *text) // Draw control //-------------------------------------------------------------------- - if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar + if (text != NULL) result = GuiStatusBar(statusBar, text); // Draw panel header as status bar GuiDrawRectangle(bounds, RAYGUI_PANEL_BORDER_WIDTH, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)), GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BASE_COLOR_DISABLED : (int)BACKGROUND_COLOR))); @@ -1784,81 +1850,6 @@ int GuiPanel(Rectangle bounds, const char *text) return result; } -// Tab Bar control -// NOTE: Using GuiToggle() for the TABS -int GuiTabBar(Rectangle bounds, char **text, int count, int *active) -{ - #define RAYGUI_TABBAR_ITEM_WIDTH 148 - - int result = -1; - //GuiState state = guiState; - - Rectangle tabBounds = { bounds.x, bounds.y, RAYGUI_TABBAR_ITEM_WIDTH, bounds.height }; - - if (*active < 0) *active = 0; - else if (*active > count - 1) *active = count - 1; - - int offsetX = 0; // Required in case tabs go out of screen - offsetX = (*active + 2)*RAYGUI_TABBAR_ITEM_WIDTH - GetScreenWidth(); - if (offsetX < 0) offsetX = 0; - - bool toggle = false; // Required for individual toggles - - // Draw control - //-------------------------------------------------------------------- - for (int i = 0; i < count; i++) - { - tabBounds.x = bounds.x + (RAYGUI_TABBAR_ITEM_WIDTH + 4)*i - offsetX; - - if (tabBounds.x < GetScreenWidth()) - { - // Draw tabs as toggle controls - int textAlignment = GuiGetStyle(TOGGLE, TEXT_ALIGNMENT); - int textPadding = GuiGetStyle(TOGGLE, TEXT_PADDING); - GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); - GuiSetStyle(TOGGLE, TEXT_PADDING, 8); - - if (i == (*active)) - { - toggle = true; - GuiToggle(tabBounds, text[i], &toggle); - } - else - { - toggle = false; - GuiToggle(tabBounds, text[i], &toggle); - if (toggle) *active = i; - } - - // Close tab with middle mouse button pressed - if (CheckCollisionPointRec(GUI_POINTER_POSITION, tabBounds) && IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON)) result = i; - - GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding); - GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment); - - // Draw tab close button - // NOTE: Only draw close button for current tab: if (CheckCollisionPointRec(mousePosition, tabBounds)) - int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); - int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); - GuiSetStyle(BUTTON, BORDER_WIDTH, 1); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); -#if defined(RAYGUI_NO_ICONS) - if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, "x")) result = i; -#else - if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, GuiIconText(ICON_CROSS_SMALL, NULL))) result = i; -#endif - GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); - GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); - } - } - - // Draw tab-bar bottom line - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, 1 }, 0, BLANK, GetColor(GuiGetStyle(TOGGLE, BORDER_COLOR_NORMAL))); - //-------------------------------------------------------------------- - - return result; // Return as result the current TAB closing requested -} - // Scroll Panel control int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view) { @@ -1866,7 +1857,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector #define RAYGUI_MIN_SCROLLBAR_HEIGHT 40 #define RAYGUI_MIN_MOUSE_WHEEL_SPEED 20 - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; Rectangle temp = { 0 }; @@ -1923,7 +1914,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector float horizontalMin = hasHorizontalScrollBar? ((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH); float horizontalMax = hasHorizontalScrollBar? content.width - bounds.width + (float)verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH) - (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)verticalScrollBarWidth : 0) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); - float verticalMin = hasVerticalScrollBar? 0.0f : -1.0f; + float verticalMin = -(float)GuiGetStyle(DEFAULT, BORDER_WIDTH); float verticalMax = hasVerticalScrollBar? content.height - bounds.height + (float)horizontalScrollBarWidth + (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); // Update control @@ -1973,7 +1964,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector // Draw control //-------------------------------------------------------------------- - if (text != NULL) GuiStatusBar(statusBar, text); // Draw panel header as status bar + if (text != NULL) result = GuiStatusBar(statusBar, text); // Draw panel header as status bar GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background @@ -2020,7 +2011,7 @@ int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector // Label control int GuiLabel(Rectangle bounds, const char *text) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Update control @@ -2039,7 +2030,7 @@ int GuiLabel(Rectangle bounds, const char *text) // Button control, returns true when clicked int GuiButton(Rectangle bounds, const char *text) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Update control @@ -2054,7 +2045,7 @@ int GuiButton(Rectangle bounds, const char *text) if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; - if (GUI_BUTTON_RELEASED) result = 1; + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; } } //-------------------------------------------------------------------- @@ -2067,14 +2058,14 @@ int GuiButton(Rectangle bounds, const char *text) if (state == STATE_FOCUSED) GuiTooltip(bounds); //------------------------------------------------------------------ - return result; // Button pressed: result = 1 + return result; } // Label button control int GuiLabelButton(Rectangle bounds, const char *text) { + int result = RESULT_NONE; GuiState state = guiState; - bool pressed = false; // NOTE: Force bounds.width to be all text float textWidth = (float)GuiGetTextWidth(text); @@ -2092,7 +2083,7 @@ int GuiLabelButton(Rectangle bounds, const char *text) if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; - if (GUI_BUTTON_RELEASED) pressed = true; + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; } } //-------------------------------------------------------------------- @@ -2102,13 +2093,13 @@ int GuiLabelButton(Rectangle bounds, const char *text) GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); //-------------------------------------------------------------------- - return pressed; + return result; } // Toggle Button control int GuiToggle(Rectangle bounds, const char *text, bool *active) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; bool temp = false; @@ -2128,6 +2119,8 @@ int GuiToggle(Rectangle bounds, const char *text, bool *active) { state = STATE_NORMAL; *active = !(*active); + + result = RESULT_CHANGED; } else state = STATE_FOCUSED; } @@ -2156,68 +2149,110 @@ int GuiToggle(Rectangle bounds, const char *text, bool *active) // Toggle Group control int GuiToggleGroup(Rectangle bounds, const char *text, int *active) { - #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEMS) - #define RAYGUI_TOGGLEGROUP_MAX_ITEMS 32 + int result = RESULT_NONE; + + #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE) + #define RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE 256 #endif - int result = 0; - float initBoundsX = bounds.x; + // One toggle group item text + static char itemText[RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE] = { 0 }; + memset(itemText, 0, RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE); int temp = 0; + int prevActive = (active == NULL)? 0 : *active; if (active == NULL) active = &temp; bool toggle = false; // Required for individual toggles - // Get substrings items from text (items pointers) - int rows[RAYGUI_TOGGLEGROUP_MAX_ITEMS] = { 0 }; - int itemCount = 0; - char **items = GuiTextSplit(text, ';', &itemCount, rows); + const char *textPtr = text; + bool itemReady = false; + float initBoundsX = bounds.x; + float initBoundsY = bounds.y; - int prevRow = rows[0]; - - for (int i = 0; i < itemCount; i++) + if (GuiGetStyle(TOGGLE, GROUP_WIDTH_FULL)) { - if (prevRow != rows[i]) - { - bounds.x = initBoundsX; - bounds.y += (bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING)); - prevRow = rows[i]; - } + // Calculate item width considring all horizontal items + // NOTE: bounds.height still considers individual items height + int itemCount = 1; + for (int c = 0; textPtr[c] != '\0'; c++) { if (textPtr[c] == ';') itemCount++; } + bounds.width /= itemCount; + } - if (i == (*active)) + // Text parsing needed to consider potential row and col entries (vertical/horizontal layout) + // when '\n' found move vertically next toggle, when ';' found move horizontally + for (int c = 0, k = 0, itemIndex = 0, row = 0, col = 0, exit = 0; exit == 0; c++) + { + // Process text to get items one by one + // NOTE: Setting columns and rows index properly + if (textPtr[c] == '\n') { - toggle = true; - GuiToggle(bounds, items[i], &toggle); + row++; + col = 0; + itemReady = true; + } + else if (textPtr[c] == ';') + { + col++; + itemReady = true; + } + else if (textPtr[c] == '\0') + { + itemReady = true; + exit = 1; } else { - toggle = false; - GuiToggle(bounds, items[i], &toggle); - if (toggle) *active = i; + itemText[k] = textPtr[c]; + k++; } - bounds.x += (bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING)); + if (itemReady) + { + // When a next item is ready, draw its toggle + if (itemIndex == (*active)) + { + toggle = true; + GuiToggle(bounds, itemText, &toggle); + } + else + { + toggle = false; + GuiToggle(bounds, itemText, &toggle); + if (toggle) *active = itemIndex; + } + + // Calculate next item position + bounds.x = initBoundsX + col*(bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING)); + bounds.y = initBoundsY + row*(bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING)); + + itemIndex++; + itemReady = false; + memset(itemText, 0, k + 1); + k = 0; + } } + if (prevActive != *active) result = RESULT_CHANGED; + return result; } // Toggle Slider control extended int GuiToggleSlider(Rectangle bounds, const char *text, int *active) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; int temp = 0; + int prevActive = (active == NULL)? 0 : *active; if (active == NULL) active = &temp; - //bool toggle = false; // Required for individual toggles - // Get substrings items from text (items pointers) int itemCount = 0; char **items = NULL; - if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL); + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount); Rectangle slider = { 0, // Calculated later depending on the active toggle @@ -2248,6 +2283,8 @@ int GuiToggleSlider(Rectangle bounds, const char *text, int *active) if (*active >= itemCount) *active = 0; slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH) + (*active + 1)*GuiGetStyle(SLIDER, SLIDER_PADDING) + (*active)*slider.width; + + if (prevActive != *active) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -2279,7 +2316,7 @@ int GuiToggleSlider(Rectangle bounds, const char *text, int *active) // Check Box control, returns 1 when state changed int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; bool temp = false; @@ -2318,7 +2355,8 @@ int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) if (GUI_BUTTON_RELEASED) { *checked = !(*checked); - result = 1; + + result = RESULT_CHANGED; } } } @@ -2346,10 +2384,11 @@ int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) // Combo Box control int GuiComboBox(Rectangle bounds, const char *text, int *active) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; int temp = 0; + int prevActive = (active == NULL)? 0 : *active; if (active == NULL) active = &temp; bounds.width -= (GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH) + GuiGetStyle(COMBOBOX, COMBO_BUTTON_SPACING)); @@ -2359,7 +2398,7 @@ int GuiComboBox(Rectangle bounds, const char *text, int *active) // Get substrings items from text (items pointers, lengths and count) int itemCount = 0; - char **items = GuiTextSplit(text, ';', &itemCount, NULL); + char **items = GuiTextSplit(text, ';', &itemCount); if (*active < 0) *active = 0; else if (*active > (itemCount - 1)) *active = itemCount - 1; @@ -2373,16 +2412,18 @@ int GuiComboBox(Rectangle bounds, const char *text, int *active) if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + if (GUI_BUTTON_PRESSED) { *active += 1; if (*active >= itemCount) *active = 0; // Cyclic combobox } - - if (GUI_BUTTON_DOWN) state = STATE_PRESSED; - else state = STATE_FOCUSED; } } + + if (prevActive != *active) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -2411,10 +2452,11 @@ int GuiComboBox(Rectangle bounds, const char *text, int *active) // NOTE: Returns mouse click int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; int temp = 0; + int prevActive = (active == NULL)? 0 : *active; if (active == NULL) active = &temp; int itemSelected = *active; @@ -2425,7 +2467,7 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod // Get substrings items from text (items pointers, lengths and count) int itemCount = 0; - char **items = GuiTextSplit(text, ';', &itemCount, NULL); + char **items = GuiTextSplit(text, ';', &itemCount); Rectangle boundsOpen = bounds; boundsOpen.height = (itemCount + 1)*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); @@ -2525,7 +2567,8 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 }, TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); #else - GuiDrawText(direction? "#121#" : "#120#", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 }, + GuiDrawText(direction? GuiIconText(ICON_ARROW_UP_FILL, NULL) : GuiIconText(ICON_ARROW_DOWN_FILL, NULL), + RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 }, TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); // ICON_ARROW_DOWN_FILL #endif } @@ -2533,8 +2576,9 @@ int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMod *active = itemSelected; - // TODO: Use result to return more internal states: mouse-press out-of-bounds, mouse-press over selected-item... - return result; // Mouse click: result = 1 + if (prevActive != *active) result = RESULT_CHANGED; + + return result; } // Text Box control @@ -2548,10 +2592,10 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) #define RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY 1 // Frames delay for autocursor movement #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; - bool multiline = false; // TODO: Consider multiline text input + bool multiline = false; int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); Rectangle textBounds = GetTextBounds(TEXTBOX, bounds); @@ -2598,7 +2642,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) { // GLOBAL: Auto-cursor movement logic // NOTE: Keystrokes are handled repeatedly when button is held down for some time - if (GUI_KEY_DOWN(KEY_LEFT) || GUI_KEY_DOWN(KEY_RIGHT) || GUI_KEY_DOWN(KEY_UP) || GUI_KEY_DOWN(KEY_DOWN) || GUI_KEY_DOWN(KEY_BACKSPACE) || GUI_KEY_DOWN(KEY_DELETE)) autoCursorCounter++; + if (GUI_KEY_DOWN(KEY_LEFT) || GUI_KEY_DOWN(KEY_RIGHT) || + GUI_KEY_DOWN(KEY_UP) || GUI_KEY_DOWN(KEY_DOWN) || + GUI_KEY_DOWN(KEY_BACKSPACE) || GUI_KEY_DOWN(KEY_DELETE)) autoCursorCounter++; else autoCursorCounter = 0; bool autoCursorShouldTrigger = (autoCursorCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN) && ((autoCursorCounter % RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0); @@ -2656,6 +2702,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) textBoxCursorIndex += pasteLength; textLength += pasteLength; text[textLength] = '\0'; + + //result = RESULT_CHANGED; } } } @@ -2674,6 +2722,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) // Make sure text last character is EOL text[textLength] = '\0'; + + //result = RESULT_CHANGED; } // Move cursor to start @@ -2696,8 +2746,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) bool puctuation = ispunct(nextCodepoint & 0xff); while (offset < textLength) { - if ((puctuation && !ispunct(nextCodepoint & 0xff)) || (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff)))) - break; + if ((puctuation && !ispunct(nextCodepoint & 0xff)) || + (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff)))) break; + offset += nextCodepointSize; accCodepointSize += nextCodepointSize; nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); @@ -2717,9 +2768,11 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) for (int i = offset; i <= textLength; i++) text[i - accCodepointSize] = text[i]; textLength -= accCodepointSize; - } - else if ((textLength > textBoxCursorIndex) && (GUI_KEY_PRESSED(KEY_DELETE) || (GUI_KEY_DOWN(KEY_DELETE) && autoCursorShouldTrigger))) + //result = RESULT_CHANGED; + } + else if ((textLength > textBoxCursorIndex) && (GUI_KEY_PRESSED(KEY_DELETE) || + (GUI_KEY_DOWN(KEY_DELETE) && autoCursorShouldTrigger))) { // Delete single codepoint from text, after current cursor position @@ -2730,10 +2783,13 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) for (int i = textBoxCursorIndex + nextCodepointSize; i <= textLength; i++) text[i - nextCodepointSize] = text[i]; textLength -= nextCodepointSize; + + //result = RESULT_CHANGED; } // Delete related codepoints from text, before current cursor position - if ((textBoxCursorIndex > 0) && GUI_KEY_PRESSED(KEY_BACKSPACE) && (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) + if ((textBoxCursorIndex > 0) && GUI_KEY_PRESSED(KEY_BACKSPACE) && + (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) { int offset = textBoxCursorIndex; int accCodepointSize = 0; @@ -2756,7 +2812,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) while (offset > 0) { prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize); - if ((puctuation && !ispunct(prevCodepoint & 0xff)) || (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break; + if ((puctuation && !ispunct(prevCodepoint & 0xff)) || + (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break; offset -= prevCodepointSize; accCodepointSize += prevCodepointSize; @@ -2767,8 +2824,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) textLength -= accCodepointSize; textBoxCursorIndex -= accCodepointSize; - } + //result = RESULT_CHANGED; + } else if ((textBoxCursorIndex > 0) && (GUI_KEY_PRESSED(KEY_BACKSPACE) || (GUI_KEY_DOWN(KEY_BACKSPACE) && autoCursorShouldTrigger))) { // Delete single codepoint from text, before current cursor position @@ -2782,6 +2840,8 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) textLength -= prevCodepointSize; textBoxCursorIndex -= prevCodepointSize; + + //result = RESULT_CHANGED; } // Move cursor position with keys @@ -2864,7 +2924,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) } // Move cursor position with mouse - if (CheckCollisionPointRec(mousePosition, textBounds)) // Mouse hover text + if (CheckCollisionPointRec(mousePosition, textBounds)) { float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/(float)guiFont.baseSize; int codepointIndex = 0; @@ -2917,7 +2977,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) { textBoxCursorIndex = 0; // GLOBAL: Reset the shared cursor index autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes - result = 1; + + //*editMode = false; + result = RESULT_PRESSED; } } else @@ -2930,7 +2992,9 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) { textBoxCursorIndex = textLength; // GLOBAL: Place cursor index to the end of current text autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes - result = 1; + + //*editMode = true; + result = RESULT_PRESSED; } } } @@ -2965,7 +3029,7 @@ int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) else if (state == STATE_FOCUSED) GuiTooltip(bounds); //-------------------------------------------------------------------- - return result; // Mouse button pressed: result = 1 + return result; } /* @@ -3063,21 +3127,24 @@ int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); //-------------------------------------------------------------------- + //if (tempValue != *value) result = RESULT_CHANGED; // WARNING: Stops editing + *value = tempValue; + return result; } // Value Box control, updates input text with numbers -// NOTE: Requires static variables: frameCounter int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) { #if !defined(RAYGUI_VALUEBOX_MAX_CHARS) #define RAYGUI_VALUEBOX_MAX_CHARS 32 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; + //int prevValue = *value; char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = { 0 }; snprintf(textValue, RAYGUI_VALUEBOX_MAX_CHARS + 1, "%i", *value); @@ -3164,7 +3231,7 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in if (*value > maxValue) *value = maxValue; else if (*value < minValue) *value = minValue; - result = 1; + result = RESULT_PRESSED; } } else @@ -3175,10 +3242,13 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in if (CheckCollisionPointRec(mousePoint, bounds)) { state = STATE_FOCUSED; - if (GUI_BUTTON_PRESSED) result = 1; + + if (GUI_BUTTON_PRESSED) result = RESULT_PRESSED; } } } + + //if (prevValue != *value) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3209,18 +3279,16 @@ int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, in } // Floating point Value Box control, updates input val_str with numbers -// NOTE: Requires static variables: frameCounter int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode) { #if !defined(RAYGUI_VALUEBOX_MAX_CHARS) #define RAYGUI_VALUEBOX_MAX_CHARS 32 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; - //char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = "\0"; - //snprintf(textValue, sizeof(textValue), "%2.2f", *value); + //float prevValue = *value; Rectangle textBounds = { 0 }; if (text != NULL) @@ -3305,17 +3373,21 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float if (valueHasChanged) *value = TextToFloat(textValue); - if ((GUI_KEY_PRESSED(KEY_ENTER) || GUI_KEY_PRESSED(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && GUI_BUTTON_PRESSED)) result = 1; + if ((GUI_KEY_PRESSED(KEY_ENTER) || GUI_KEY_PRESSED(KEY_KP_ENTER)) || + (!CheckCollisionPointRec(mousePoint, bounds) && GUI_BUTTON_PRESSED)) result = RESULT_PRESSED; } else { if (CheckCollisionPointRec(mousePoint, bounds)) { state = STATE_FOCUSED; - if (GUI_BUTTON_PRESSED) result = 1; + + if (GUI_BUTTON_PRESSED) result = RESULT_PRESSED; } } } + + //if (prevValue != *value) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3338,8 +3410,7 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float } // Draw text label if provided - GuiDrawText(text, textBounds, - (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, + GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); //-------------------------------------------------------------------- @@ -3350,12 +3421,13 @@ int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float // NOTE: Other GuiSlider*() controls use this one int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; float temp = (maxValue - minValue)/2.0f; if (value == NULL) value = &temp; - float oldValue = *value; + + float prevValue = *value; int sliderWidth = GuiGetStyle(SLIDER, SLIDER_WIDTH); @@ -3406,10 +3478,6 @@ int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, flo else if (*value < minValue) *value = minValue; } - // Control value change check - if (oldValue == *value) result = 0; - else result = 1; - // Slider bar limits check float sliderValue = (((*value - minValue)/(maxValue - minValue))*(bounds.width - sliderWidth - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))); if (sliderWidth > 0) // Slider @@ -3425,6 +3493,8 @@ int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, flo slider.width = sliderValue; if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH); } + + if (prevValue != *value) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3467,7 +3537,7 @@ int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, flo // Slider Bar control extended, returns selected value int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) { - int result = 0; + int result = RESULT_NONE; int preSliderWidth = GuiGetStyle(SLIDER, SLIDER_WIDTH); GuiSetStyle(SLIDER, SLIDER_WIDTH, 0); result = GuiSlider(bounds, textLeft, textRight, value, minValue, maxValue); @@ -3479,11 +3549,12 @@ int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, // Progress Bar control extended, shows current progress value int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; float temp = (maxValue - minValue)/2.0f; if (value == NULL) value = &temp; + float prevValue = *value; // Progress bar Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), @@ -3496,6 +3567,8 @@ int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight // WARNING: Working with floats could lead to rounding issues if ((state != STATE_DISABLED)) progress.width = ((float)*value/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)); + + if (prevValue != *value) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3566,9 +3639,26 @@ int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight // Status Bar control int GuiStatusBar(Rectangle bounds, const char *text) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check checkbox state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + //if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + //else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; + } + } + //-------------------------------------------------------------------- + // Draw control //-------------------------------------------------------------------- GuiDrawRectangle(bounds, GuiGetStyle(STATUSBAR, BORDER_WIDTH), GetColor(GuiGetStyle(STATUSBAR, BORDER + (state*3))), GetColor(GuiGetStyle(STATUSBAR, BASE + (state*3)))); @@ -3581,7 +3671,7 @@ int GuiStatusBar(Rectangle bounds, const char *text) // Dummy rectangle control, intended for placeholding int GuiDummyRec(Rectangle bounds, const char *text) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; // Update control @@ -3595,6 +3685,8 @@ int GuiDummyRec(Rectangle bounds, const char *text) { if (GUI_BUTTON_DOWN) state = STATE_PRESSED; else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; } } //-------------------------------------------------------------------- @@ -3611,25 +3703,26 @@ int GuiDummyRec(Rectangle bounds, const char *text) // List View control int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active) { - int result = 0; + int result = RESULT_NONE; int itemCount = 0; char **items = NULL; - if (text != NULL) items = GuiTextSplit(text, ';', &itemCount, NULL); + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount); result = GuiListViewEx(bounds, items, itemCount, scrollIndex, active, NULL); return result; } -// List View control with extended parameters +// List View control using text entries list and returning focus entry int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; int itemFocused = (focus == NULL)? -1 : *focus; int itemSelected = (active == NULL)? -1 : *active; + int prevActive = (active == NULL)? 0 : *active; // Check if scroll bar is needed bool useScrollBar = false; @@ -3767,35 +3860,132 @@ int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, in if (focus != NULL) *focus = itemFocused; if (scrollIndex != NULL) *scrollIndex = startIndex; + if (prevActive != *active) result = RESULT_CHANGED; + return result; } -// Color Panel control - Color (RGBA) variant +// Tab Bar control +int GuiTabBar(Rectangle bounds, const char *text, int *hscroll, int *active) +{ + int result = RESULT_NONE; + int itemCount = 0; + char **items = NULL; + + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount); + + result = GuiTabBarEx(bounds, items, itemCount, hscroll, active, NULL); + + return result; +} + +// Tab Bar control, using text entries list and returning focus entry +// NOTE: In case of tab close result, consider focused tab +// TODO: Reeplace GuiToggle() usage for custom implementation for the TABS +int GuiTabBarEx(Rectangle bounds, char **text, int count, int *hscroll, int *active, int *focus) +{ + int result = RESULT_NONE; + //GuiState state = guiState; + + int tabItemsWidth = GuiGetStyle(TABBAR, TAB_ITEMS_WIDTH); + Rectangle tabBounds = { bounds.x, bounds.y, (float)tabItemsWidth, bounds.height }; + + if (*active < 0) *active = 0; + else if (*active > count - 1) *active = count - 1; + + int prevActive = (active == NULL)? 0 : *active; + + int offsetX = 0; // Required in case tabs go out of screen + offsetX = (*active*tabItemsWidth) - GetScreenWidth(); + if (offsetX < 0) offsetX = 0; + + bool toggle = false; // Required for individual toggles + + // Draw control + //-------------------------------------------------------------------- + //if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) // TODO: Support disabled + + for (int i = 0; i < count; i++) + { + tabBounds.x = bounds.x + (tabItemsWidth + 4)*i + offsetX; + + if (tabBounds.x < GetScreenWidth()) + { + // Draw tabs as toggle controls + int textAlignment = GuiGetStyle(TOGGLE, TEXT_ALIGNMENT); + int textPadding = GuiGetStyle(TOGGLE, TEXT_PADDING); + GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(TOGGLE, TEXT_PADDING, 8); + + if (i == (*active)) + { + toggle = true; + GuiToggle(tabBounds, text[i], &toggle); + } + else + { + toggle = false; + GuiToggle(tabBounds, text[i], &toggle); + if (toggle) *active = i; + } + + // Close tab with middle mouse button pressed + if (CheckCollisionPointRec(GUI_POINTER_POSITION, tabBounds) && GUI_BUTTON_PRESSED_MID) result = RESULT_TAB_CLOSE; + + GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding); + GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment); + + if (GuiGetStyle(TABBAR, TAB_CLOSE_BUTTON)) + { + // Draw tab close button + // NOTE: Only draw close button for current tab: if (CheckCollisionPointRec(mousePosition, tabBounds)) + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 1); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); +#if defined(RAYGUI_NO_ICONS) + if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, "x")) result = RESULT_TAB_CLOSE; +#else + if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, + GuiIconText(ICON_CROSS_SMALL, NULL))) result = RESULT_TAB_CLOSE; +#endif + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); + } + } + } + + // Draw tab-bar bottom line + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, 1 }, 0, BLANK, GetColor(GuiGetStyle(TABBAR, BORDER_COLOR_NORMAL))); + //-------------------------------------------------------------------- + + // NOTE: In case of tab close result, consider focused tab + if ((result != RESULT_TAB_CLOSE) && (prevActive != *active)) result = RESULT_CHANGED; + + return result; +} + +// Color Panel control int GuiColorPanel(Rectangle bounds, const char *text, Color *color) { - int result = 0; + int result = RESULT_NONE; Vector3 vcolor = { (float)color->r/255.0f, (float)color->g/255.0f, (float)color->b/255.0f }; Vector3 hsv = ConvertRGBtoHSV(vcolor); - Vector3 prevHsv = hsv; // workaround to see if GuiColorPanelHSV modifies the hsv + Vector3 prevHsv = hsv; // NOTE: Workaround to see if GuiColorPanelHSV() modifies the hsv - GuiColorPanelHSV(bounds, text, &hsv); + result = GuiColorPanelHSV(bounds, text, &hsv); // Check if the hsv was changed, only then change the color // This is required, because the Color->HSV->Color conversion has precision errors // Thus the assignment from HSV to Color should only be made, if the HSV has a new user-entered value // Otherwise GuiColorPanel would often modify it's color without user input - // TODO: GuiColorPanelHSV could return 1 if the slider was dragged, to simplify this check - if (hsv.x != prevHsv.x || hsv.y != prevHsv.y || hsv.z != prevHsv.z) + if ((hsv.x != prevHsv.x) || (hsv.y != prevHsv.y) || (hsv.z != prevHsv.z)) { Vector3 rgb = ConvertHSVtoRGB(hsv); - - // NOTE: Vector3ToColor() only available on raylib 1.8.1 - *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x), - (unsigned char)(255.0f*rgb.y), - (unsigned char)(255.0f*rgb.z), - color->a }; + *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x), (unsigned char)(255.0f*rgb.y), (unsigned char)(255.0f*rgb.z), color->a }; } + return result; } @@ -3807,8 +3997,10 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) #define RAYGUI_COLORBARALPHA_CHECKED_SIZE 10 #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; + + float prevAlpha = *alpha; Rectangle selector = { (float)bounds.x + (*alpha)*bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.y - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT), @@ -3855,6 +4047,8 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) else state = STATE_FOCUSED; } } + + if (prevAlpha != *alpha) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3895,8 +4089,10 @@ int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) // float GuiColorBarLuminance() [BLACK->WHITE] int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; + + float prevHue = *hue; Rectangle selector = { (float)bounds.x - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)bounds.y + (*hue)/360.0f*bounds.height - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2, (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT) }; // Update control @@ -3951,6 +4147,8 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) }*/ } } + + if (prevHue != *hue) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -3958,15 +4156,32 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) if (state != STATE_DISABLED) { // Draw hue bar:color bars - // TODO: Use directly DrawRectangleGradientEx(bounds, color1, color2, color2, color1); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + bounds.height/6), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 2*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 3*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 4*(bounds.height/6)), (int)bounds.width, (int)ceilf(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha)); - DrawRectangleGradientV((int)bounds.x, (int)(bounds.y + 5*(bounds.height/6)), (int)bounds.width, (int)(bounds.height/6), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha)); + // NOTE: Using DrawRectangleGradientEx(bounds, color1, color2, color2, color1); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 1*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 2*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 3*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 4*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 5*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha)); + } + else + { + DrawRectangleGradientEx(bounds, + Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), + Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha)); } - else DrawRectangleGradientV((int)bounds.x, (int)bounds.y, (int)bounds.width, (int)bounds.height, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha)); GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); @@ -3986,12 +4201,12 @@ int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) // NOTE: this picker converts RGB to HSV, which can cause the Hue control to jump. If you have this problem, consider using the HSV variant instead int GuiColorPicker(Rectangle bounds, const char *text, Color *color) { - int result = 0; + int result = RESULT_NONE; Color temp = { 200, 0, 0, 255 }; if (color == NULL) color = &temp; - GuiColorPanel(bounds, NULL, color); + result = GuiColorPanel(bounds, NULL, color); Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; //Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) }; @@ -3999,7 +4214,7 @@ int GuiColorPicker(Rectangle bounds, const char *text, Color *color) // NOTE: this conversion can cause low hue-resolution, if the r, g and b value are very similar, which causes the hue bar to shift around when only the GuiColorPanel is used Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ (*color).r/255.0f, (*color).g/255.0f, (*color).b/255.0f }); - GuiColorBarHue(boundsHue, NULL, &hsv.x); + if (result != RESULT_CHANGED) result = GuiColorBarHue(boundsHue, NULL, &hsv.x); //color.a = (unsigned char)(GuiColorBarAlpha(boundsAlpha, (float)color.a/255.0f)*255.0f); Vector3 rgb = ConvertHSVtoRGB(hsv); @@ -4018,7 +4233,7 @@ int GuiColorPicker(Rectangle bounds, const char *text, Color *color) // NOTE: bounds define GuiColorPanelHSV() size int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) { - int result = 0; + int result = RESULT_NONE; Vector3 tempHsv = { 0 }; @@ -4029,11 +4244,11 @@ int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) colorHsv = &tempHsv; } - GuiColorPanelHSV(bounds, NULL, colorHsv); + result = GuiColorPanelHSV(bounds, NULL, colorHsv); - const Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; + Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; - GuiColorBarHue(boundsHue, NULL, &colorHsv->x); + if (result == RESULT_NONE) result = GuiColorBarHue(boundsHue, NULL, &colorHsv->x); return result; } @@ -4041,10 +4256,11 @@ int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) // Color Panel control - HSV variant int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) { - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; - Vector2 pickerSelector = { 0 }; + Vector3 prevColorHsv = *colorHsv; + Vector2 pickerSelector = { 0 }; const Color colWhite = { 255, 255, 255, 255 }; const Color colBlack = { 0, 0, 0, 255 }; @@ -4053,9 +4269,7 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) Vector3 maxHue = { colorHsv->x, 1.0f, 1.0f }; Vector3 rgbHue = ConvertHSVtoRGB(maxHue); - Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x), - (unsigned char)(255.0f*rgbHue.y), - (unsigned char)(255.0f*rgbHue.z), 255 }; + Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x), (unsigned char)(255.0f*rgbHue.y), (unsigned char)(255.0f*rgbHue.z), 255 }; // Update control //-------------------------------------------------------------------- @@ -4079,12 +4293,11 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) // Calculate color from picker Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y }; - colorPick.x /= (float)bounds.width; // Get normalized value on x - colorPick.y /= (float)bounds.height; // Get normalized value on y + colorPick.x /= (float)bounds.width; // Get normalized value on x + colorPick.y /= (float)bounds.height; // Get normalized value on y colorHsv->y = colorPick.x; colorHsv->z = 1.0f - colorPick.y; - } } else @@ -4114,6 +4327,10 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) else state = STATE_FOCUSED; } } + + if ((prevColorHsv.x != colorHsv->x) || + (prevColorHsv.y != colorHsv->y) || + (prevColorHsv.z != colorHsv->z)) result = RESULT_CHANGED; //-------------------------------------------------------------------- // Draw control @@ -4139,7 +4356,8 @@ int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) } // Message Box control -int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *buttons) +// NOTE: Button pressed is returned through btnActive parameter, 0 for window close button +int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *btnText, int *btnActive) { #if !defined(RAYGUI_MESSAGEBOX_BUTTON_HEIGHT) #define RAYGUI_MESSAGEBOX_BUTTON_HEIGHT 24 @@ -4148,10 +4366,10 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons #define RAYGUI_MESSAGEBOX_BUTTON_PADDING 12 #endif - int result = -1; // Returns clicked button from buttons list, 0 refers to closed window button + int result = RESULT_NONE; int buttonCount = 0; - char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL); + char **btnTextList = GuiTextSplit(btnText, ';', &buttonCount); Rectangle buttonBounds = { 0 }; buttonBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING; buttonBounds.y = bounds.y + bounds.height - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT - RAYGUI_MESSAGEBOX_BUTTON_PADDING; @@ -4168,7 +4386,11 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons // Draw control //-------------------------------------------------------------------- - if (GuiWindowBox(bounds, title)) result = 0; + if (GuiWindowBox(bounds, title) == RESULT_PRESSED) + { + *btnActive = 0; + result = RESULT_PRESSED; + } int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); @@ -4180,7 +4402,11 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons for (int i = 0; i < buttonCount; i++) { - if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1; + if (GuiButton(buttonBounds, btnTextList[i])) + { + *btnActive = i + 1; + result = RESULT_PRESSED; + } buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING); } @@ -4190,8 +4416,9 @@ int GuiMessageBox(Rectangle bounds, const char *title, const char *message, cons return result; } -// Text Input Box control, ask for text -int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, const char *buttons, char *text, int textMaxSize, bool *secretViewActive) +// Text Input Box control +// NOTE: Button pressed is returned through btnActive parameter, 0 for window close button +int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, char *text, int textSize, const char *btnText, int *btnActive, bool *secretViewActive) { #if !defined(RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT) #define RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT 24 @@ -4203,14 +4430,14 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co #define RAYGUI_TEXTINPUTBOX_HEIGHT 26 #endif + int result = RESULT_NONE; + // Used to enable text edit mode // WARNING: No more than one GuiTextInputBox() should be open at the same time static bool textEditMode = false; - int result = -1; - int buttonCount = 0; - char **buttonsText = GuiTextSplit(buttons, ';', &buttonCount, NULL); + char **btnTextList = GuiTextSplit(btnText, ';', &buttonCount); Rectangle buttonBounds = { 0 }; buttonBounds.x = bounds.x + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; buttonBounds.y = bounds.y + bounds.height - RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; @@ -4240,7 +4467,11 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co // Draw control //-------------------------------------------------------------------- - if (GuiWindowBox(bounds, title)) result = 0; + if (GuiWindowBox(bounds, title) == RESULT_PRESSED) + { + *btnActive = 0; + result = RESULT_PRESSED; + } // Draw message if available if (message != NULL) @@ -4258,13 +4489,20 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co { static char stars[] = "****************"; if (GuiTextBox(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x, textBoxBounds.y, textBoxBounds.width - 4 - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.height }, - ((*secretViewActive == 1) || textEditMode)? text : stars, textMaxSize, textEditMode)) textEditMode = !textEditMode; + ((*secretViewActive == 1) || textEditMode)? text : stars, textSize, textEditMode) == RESULT_PRESSED) textEditMode = !textEditMode; - GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, (*secretViewActive == 1)? "#44#" : "#45#", secretViewActive); +#if defined(RAYGUI_NO_ICONS) + GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, + (*secretViewActive == 1)? "O" : "*", secretViewActive); +#else + GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, + (*secretViewActive == 1)? GuiIconText(ICON_EYE_ON, NULL) : GuiIconText(ICON_EYE_OFF, NULL), secretViewActive); +#endif } else { - if (GuiTextBox(textBoxBounds, text, textMaxSize, textEditMode)) textEditMode = !textEditMode; + if (GuiTextBox(textBoxBounds, text, textSize, textEditMode) == RESULT_PRESSED) + textEditMode = !textEditMode; } GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, prevTextBoxAlignment); @@ -4274,16 +4512,21 @@ int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, co for (int i = 0; i < buttonCount; i++) { - if (GuiButton(buttonBounds, buttonsText[i])) result = i + 1; + if (GuiButton(buttonBounds, btnTextList[i])) + { + *btnActive = i + 1; + result = RESULT_PRESSED; + } + buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING); } - if (result >= 0) textEditMode = false; + if (result == RESULT_PRESSED) textEditMode = false; GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevBtnTextAlignment); //-------------------------------------------------------------------- - return result; // Result is the pressed button index + return result; } // Grid control @@ -4297,7 +4540,7 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect #define RAYGUI_GRID_ALPHA 0.15f #endif - int result = 0; + int result = RESULT_NONE; GuiState state = guiState; Vector2 mousePoint = GUI_POINTER_POSITION; @@ -4318,6 +4561,8 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect // NOTE: Cell values must be the upper left of the cell the mouse is in currentMouseCell.x = floorf((mousePoint.x - bounds.x)/spacing); currentMouseCell.y = floorf((mousePoint.y - bounds.y)/spacing); + + result = RESULT_PRESSED; } } //-------------------------------------------------------------------- @@ -4344,6 +4589,7 @@ int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vect } if (mouseCell != NULL) *mouseCell = currentMouseCell; + return result; } @@ -4387,11 +4633,16 @@ void GuiLoadStyle(const char *fileName) int controlId = 0; int propertyId = 0; unsigned int propertyValue = 0; + unsigned int version = 0; while (!feof(rgsFile)) { switch (buffer[0]) { + case 'v': + { + sscanf(buffer, "v %d", &version); + } case 'p': { // Style property: p @@ -4402,12 +4653,17 @@ void GuiLoadStyle(const char *fileName) } break; case 'f': { - // Style font: f + // Style font: f int fontSize = 0; - char charmapFileName[256] = { 0 }; - char fontFileName[256] = { 0 }; - sscanf(buffer, "f %d %s %[^\r\n]s", &fontSize, charmapFileName, fontFileName); + char charmapFileName[32] = { 0 }; + char fontFileName[32] = { 0 }; + + if (version >= 600) sscanf(buffer, "f %d %31s %31[^\r\n]s", &fontSize, fontFileName, charmapFileName); + else sscanf(buffer, "f %d %31s %31[^\r\n]s", &fontSize, charmapFileName, fontFileName); + + // GLOBAL: Copy font file name into guiFontName + snprintf(guiFontName, 32, "%s", fontFileName); Font font = { 0 }; int *codepoints = NULL; @@ -4483,6 +4739,318 @@ void GuiLoadStyle(const char *fileName) } } +// Load style from memory +// WARNING: Binary files only +void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize) +{ + // Style File Structure (.rgs) + // ------------------------------------------------------ + // Offset | Size | Type | Description + // ------------------------------------------------------ + // 0 | 4 | char | Signature: "rGS " + // 4 | 2 | short | Version: 200, 400, 600 + // 6 | 2 | short | reserved + // 8 | 4 | int | Num properties (only changed ones from default style) + + // Properties Data (8 bytes per property) + // WARNING: Only properties required that differ from default (light) internal style + // foreach (property) + // { + // 8+8*i | 2 | short | ControlId + // 8+8*i | 2 | short | PropertyId + // 8+8*i | 4 | int | PropertyValue + // } + + // Custom Font Data : Parameters (64 bytes) + // ... | 4 | int | Font data size (0 - no font, no more fields added!) + // ... | 32 | char | Font filename (with extension) - VERSION: >=600 + // ... | 4 | int | Font base size + // ... | 4 | int | Font glyph count [glyphCount] + // ... | 4 | int | Font type (0-NORMAL, 1-SDF) + // ... | 16 | Rectangle | Font white rectangle + + // Custom Font Data : Image (20 bytes + imData) + // NOTE: Font image atlas is always converted to GRAY+ALPHA + // and atlas image data can be compressed (DEFLATE) + // ... | 4 | int | Image data size (uncompressed) + // ... | 4 | int | Image data size (compressed) + // ... | 4 | int | Image width + // ... | 4 | int | Image height + // ... | 4 | int | Image format: GRAY+ALPHA (expected) + // ... | imSize | byte | Image data (comp or uncomp) + + // Custom Font Data : Recs (32 bytes*glyphCount) + // NOTE: Font recs data can be compressed (DEFLATE) + // ... | 4 | int | Recs data compressed size (0 - not compressed, 1-compressed) - VERSION: >=400 + // + // if (compRecsSize == 0) + // { + // NOTE: Uncompressed size can be calculated: (glyphCount*16 byte) + // foreach (glyph) + // { + // ... | 16 | Rectangle | Glyph rectangle (in image) + // } + // } + // else + // { + // ... | compRecsSize | byte | Rectangles data + // } + // + + // Custom Font Data : Glyph Info (32 bytes*glyphCount) + // NOTE: Font glyphs info data can be compressed (DEFLATE) + // ... | 4 | int | Glyphs data compressed size (0 - not compressed) - VERSION: >=400 + // + // if (compGlyphsSize == 0) + // { + // NOTE: Uncompressed size can be calculated: (glyphCount*16 byte) + // foreach (glyph) + // { + // ... | 4 | int | Glyph value + // ... | 4 | int | Glyph offset X + // ... | 4 | int | Glyph offset Y + // ... | 4 | int | Glyph advance X + // } + // } + // else + // { + // ... | compGlyphsSize | byte | Glyphs data + // } + // ------------------------------------------------------ + + unsigned char *fileDataPtr = (unsigned char *)fileData; + + char signature[5] = { 0 }; + short version = 0; + short reserved = 0; + int propertyCount = 0; + + memcpy(signature, fileDataPtr, 4); + memcpy(&version, fileDataPtr + 4, sizeof(short)); + memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short)); + memcpy(&propertyCount, fileDataPtr + 4 + 2 + 2, sizeof(int)); + fileDataPtr += 12; + + if ((signature[0] == 'r') && + (signature[1] == 'G') && + (signature[2] == 'S') && + (signature[3] == ' ')) + { + short controlId = 0; + short propertyId = 0; + unsigned int propertyValue = 0; + + for (int i = 0; i < propertyCount; i++) + { + memcpy(&controlId, fileDataPtr, sizeof(short)); + memcpy(&propertyId, fileDataPtr + 2, sizeof(short)); + memcpy(&propertyValue, fileDataPtr + 2 + 2, sizeof(unsigned int)); + fileDataPtr += 8; + + if (controlId == 0) // DEFAULT control + { + // If a DEFAULT property is loaded, it is propagated to all controls + // NOTE: All DEFAULT properties should be defined first in the file + GuiSetStyle(0, (int)propertyId, propertyValue); + + if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int j = 1; j < RAYGUI_MAX_CONTROLS; j++) GuiSetStyle(j, (int)propertyId, propertyValue); + } + else GuiSetStyle((int)controlId, (int)propertyId, propertyValue); + } + + // Load custom font if available + // NOTE: Font texture loading requires raylib + int fontDataSize = 0; + memcpy(&fontDataSize, fileDataPtr, sizeof(int)); + fileDataPtr += 4; + + if (fontDataSize > 0) + { + Font font = { 0 }; + int fontType = 0; // 0-Normal, 1-SDF + + // WARNING: Version 600 adds 32 bytes for the font filename (with extension) + if (version >= 600) + { + // GLOBAL: Copy font file name into guiFontName + memcpy(guiFontName, fileDataPtr, 32); + fileDataPtr += 32; + } + else memset(guiFontName, 0, 32); + + memcpy(&font.baseSize, fileDataPtr, sizeof(int)); + memcpy(&font.glyphCount, fileDataPtr + 4, sizeof(int)); + memcpy(&fontType, fileDataPtr + 4 + 4, sizeof(int)); + fileDataPtr += 12; + + // Load font white rectangle + Rectangle fontWhiteRec = { 0 }; + memcpy(&fontWhiteRec, fileDataPtr, sizeof(Rectangle)); + fileDataPtr += 16; + + // Load font image parameters + int fontImageUncompSize = 0; + int fontImageCompSize = 0; + memcpy(&fontImageUncompSize, fileDataPtr, sizeof(int)); + memcpy(&fontImageCompSize, fileDataPtr + 4, sizeof(int)); + fileDataPtr += 8; + + Image imFont = { 0 }; + imFont.mipmaps = 1; + memcpy(&imFont.width, fileDataPtr, sizeof(int)); + memcpy(&imFont.height, fileDataPtr + 4, sizeof(int)); + memcpy(&imFont.format, fileDataPtr + 4 + 4, sizeof(int)); + fileDataPtr += 12; + + if ((fontImageCompSize > 0) && (fontImageCompSize != fontImageUncompSize)) + { + // Compressed font atlas image data (DEFLATE), it requires DecompressData() + int dataUncompSize = 0; + unsigned char *compData = (unsigned char *)RAYGUI_CALLOC(fontImageCompSize, sizeof(unsigned char)); + memcpy(compData, fileDataPtr, fontImageCompSize); + fileDataPtr += fontImageCompSize; + + imFont.data = DecompressData(compData, fontImageCompSize, &dataUncompSize); + + // Security check, dataUncompSize must match the provided fontImageUncompSize + if (dataUncompSize != fontImageUncompSize) RAYGUI_LOG("WARNING: Uncompressed font atlas image data could be corrupted"); + + RAYGUI_FREE(compData); + } + else + { + // Font atlas image data is not compressed + imFont.data = (unsigned char *)RAYGUI_CALLOC(fontImageUncompSize, sizeof(unsigned char)); + memcpy(imFont.data, fileDataPtr, fontImageUncompSize); + fileDataPtr += fontImageUncompSize; + } + + // Load font recs data (glyphs position and size in the image atlas) + int recsDataSize = font.glyphCount*sizeof(Rectangle); + int recsDataCompressedSize = 0; + + // WARNING: Version 400 adds the compression size parameter + if (version >= 400) + { + // RGS files version 400 support compressed recs data + memcpy(&recsDataCompressedSize, fileDataPtr, sizeof(int)); + fileDataPtr += sizeof(int); + } + + if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize)) + { + // Recs data is compressed, uncompress it + unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_CALLOC(recsDataCompressedSize, sizeof(unsigned char)); + + memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize); + fileDataPtr += recsDataCompressedSize; + + int recsDataUncompSize = 0; + font.recs = (Rectangle *)DecompressData(recsDataCompressed, recsDataCompressedSize, &recsDataUncompSize); + + // Security check, data uncompressed size must match the expected original data size + if (recsDataUncompSize != recsDataSize) RAYGUI_LOG("WARNING: Uncompressed font recs data could be corrupted"); + + RAYGUI_FREE(recsDataCompressed); + } + else + { + // Recs data is uncompressed + font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle)); + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.recs[i], fileDataPtr, sizeof(Rectangle)); + fileDataPtr += sizeof(Rectangle); + } + } + + // Load font glyphs info data + int glyphsDataSize = font.glyphCount*16; // 16 bytes data per glyph + int glyphsDataCompressedSize = 0; + + // WARNING: Version 400 adds the compression size parameter + if (version >= 400) + { + // RGS files version 400 support compressed glyphs data + memcpy(&glyphsDataCompressedSize, fileDataPtr, sizeof(int)); + fileDataPtr += sizeof(int); + } + + // Allocate required glyphs space to fill with data + font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo)); + + if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize)) + { + // Glyphs data is compressed, uncompress it + unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_CALLOC(glyphsDataCompressedSize, sizeof(unsigned char)); + + memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize); + fileDataPtr += glyphsDataCompressedSize; + + int glyphsDataUncompSize = 0; + unsigned char *glyphsDataUncomp = DecompressData(glypsDataCompressed, glyphsDataCompressedSize, &glyphsDataUncompSize); + + // Security check, data uncompressed size must match the expected original data size + if (glyphsDataUncompSize != glyphsDataSize) RAYGUI_LOG("WARNING: Uncompressed font glyphs data could be corrupted"); + + unsigned char *glyphsDataUncompPtr = glyphsDataUncomp; + + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.glyphs[i].value, glyphsDataUncompPtr, sizeof(int)); + memcpy(&font.glyphs[i].offsetX, glyphsDataUncompPtr + 4, sizeof(int)); + memcpy(&font.glyphs[i].offsetY, glyphsDataUncompPtr + 8, sizeof(int)); + memcpy(&font.glyphs[i].advanceX, glyphsDataUncompPtr + 12, sizeof(int)); + glyphsDataUncompPtr += 16; + } + + RAYGUI_FREE(glypsDataCompressed); + RAYGUI_FREE(glyphsDataUncomp); + } + else + { + // Glyphs data is uncompressed + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.glyphs[i].value, fileDataPtr, sizeof(int)); + memcpy(&font.glyphs[i].offsetX, fileDataPtr + 4, sizeof(int)); + memcpy(&font.glyphs[i].offsetY, fileDataPtr + 8, sizeof(int)); + memcpy(&font.glyphs[i].advanceX, fileDataPtr + 12, sizeof(int)); + fileDataPtr += 16; + } + } + +#if defined(RAYGUI_FONT_ICONS_BAKING) + // Font atlas image icons baking + Rectangle updatedWhiteRec = { 0 }; + guiIconFontOffsetY = GuiFontIconBaking(&imFont, font, &updatedWhiteRec); + if (guiIconFontOffsetY > 0) fontWhiteRec = updatedWhiteRec; +#endif + +#if !defined(RAYGUI_STANDALONE) + // Load texture from image + if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture); + font.texture = LoadTextureFromImage(imFont); + + // Fallback to default raylib texture if font texture loading fails + if (font.texture.id != 0) + { + // Set font texture source rectangle to be used as white texture to draw shapes + // NOTE: It makes possible to draw shapes and text (full UI) in a single draw call + if ((fontWhiteRec.x > 0) && + (fontWhiteRec.y > 0) && + (fontWhiteRec.width > 0) && + (fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec); + } + else font = GetFontDefault(); + + GuiSetFont(font); +#endif + RAYGUI_FREE(imFont.data); + } + } +} + // Load style default over global style void GuiLoadStyleDefault(void) { @@ -4515,7 +5083,7 @@ void GuiLoadStyleDefault(void) GuiSetStyle(DEFAULT, TEXT_SPACING, 1); // DEFAULT, shared by all controls GuiSetStyle(DEFAULT, LINE_COLOR, 0x90abb5ff); // DEFAULT specific property GuiSetStyle(DEFAULT, BACKGROUND_COLOR, 0xf5f5f5ff); // DEFAULT specific property - GuiSetStyle(DEFAULT, TEXT_LINE_SPACING, 5); // DEFAULT, pixels between lines, from bottom of first line to top of second + GuiSetStyle(DEFAULT, TEXT_LINE_SPACING, 12); // DEFAULT, pixels between lines, from bottom of first line to top of second GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); // DEFAULT, text aligned vertically to middle of text-bounds // Initialize control-specific property values @@ -4534,6 +5102,7 @@ void GuiLoadStyleDefault(void) GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); GuiSetStyle(STATUSBAR, TEXT_PADDING, 8); GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(TABBAR, TAB_ITEMS_WIDTH, 160); // Initialize extended property values // NOTE: By default, extended property values are initialized to 0 @@ -4583,6 +5152,9 @@ void GuiLoadStyleDefault(void) // NOTE: Setting up a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering SetShapesTexture(guiFont.texture, RAYGUI_CLITERAL(Rectangle){ whiteChar.x + 1, whiteChar.y + 1, whiteChar.width - 2, whiteChar.height - 2 }); + + // Reset baked icons offset in font + guiIconFontOffsetY = 0; } } @@ -4624,71 +5196,28 @@ const char *GuiIconText(int iconId, const char *text) unsigned int *GuiGetIcons(void) { return guiIconsPtr; } // Load raygui icons file (.rgi) -// NOTE: In case nameIds are required, they can be requested with loadIconsName, -// they are returned as a guiIconsName[iconCount][RAYGUI_ICON_MAX_NAME_LENGTH], // WARNING: guiIconsName[]][] memory should be manually freed! char **GuiLoadIcons(const char *fileName, bool loadIconsName) { - // Style File Structure (.rgi) - // ------------------------------------------------------ - // Offset | Size | Type | Description - // ------------------------------------------------------ - // 0 | 4 | char | Signature: "rGI " - // 4 | 2 | short | Version: 100 - // 6 | 2 | short | reserved - - // 8 | 2 | short | Num icons (N) - // 10 | 2 | short | Icons size (Options: 16, 32, 64) (S) - - // Icons name id (32 bytes per name id) - // foreach (icon) - // { - // 12+32*i | 32 | char | Icon NameId - // } - - // Icons data: One bit per pixel, stored as unsigned int array (depends on icon size) - // S*S pixels/32bit per unsigned int = K unsigned int per icon - // foreach (icon) - // { - // ... | K | unsigned int | Icon Data - // } - FILE *rgiFile = fopen(fileName, "rb"); - char **guiIconsName = NULL; if (rgiFile != NULL) { - char signature[5] = { 0 }; - short version = 0; - short reserved = 0; - short iconCount = 0; - short iconSize = 0; + unsigned char *fileData = NULL; + int dataSize = 0; - fread(signature, 1, 4, rgiFile); - fread(&version, sizeof(short), 1, rgiFile); - fread(&reserved, sizeof(short), 1, rgiFile); - fread(&iconCount, sizeof(short), 1, rgiFile); - fread(&iconSize, sizeof(short), 1, rgiFile); + fseek(rgiFile, 0, SEEK_END); + int size = (int)ftell(rgiFile); + fseek(rgiFile, 0, SEEK_SET); - if ((signature[0] == 'r') && - (signature[1] == 'G') && - (signature[2] == 'I') && - (signature[3] == ' ')) + if (size > 0) { - if (loadIconsName) - { - guiIconsName = (char **)RAYGUI_CALLOC(iconCount, sizeof(char *)); - for (int i = 0; i < iconCount; i++) - { - guiIconsName[i] = (char *)RAYGUI_CALLOC(RAYGUI_ICON_MAX_NAME_LENGTH, sizeof(char)); - fread(guiIconsName[i], 1, RAYGUI_ICON_MAX_NAME_LENGTH, rgiFile); - } - } - else fseek(rgiFile, iconCount*RAYGUI_ICON_MAX_NAME_LENGTH, SEEK_CUR); + fileData = (unsigned char *)RL_CALLOC(size, sizeof(unsigned char)); + // WARNING: File can be partially loaded but ignoring it for simplicity + dataSize = (int)fread(fileData, sizeof(unsigned char), size, rgiFile); - // Read icons data directly over internal icons array - fread(guiIconsPtr, sizeof(unsigned int), (int)iconCount*((int)iconSize*(int)iconSize/32), rgiFile); + guiIconsName = GuiLoadIconsFromMemory(fileData, dataSize, loadIconsName); } fclose(rgiFile); @@ -4698,9 +5227,34 @@ char **GuiLoadIcons(const char *fileName, bool loadIconsName) } // Load icons from memory -// WARNING: Binary files only +// GLOBAL: Updates global variable: guiIconsPtr char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName) { + // Icon File Structure (.rgi) + // ------------------------------------------------------ + // Offset | Size | Type | Description + // ------------------------------------------------------ + // 0 | 4 | char | Signature: "rGI " + // 4 | 2 | short | Version: 100, 500 + // 6 | 2 | short | reserved + + // 8 | 2 | short | Num icons (N) + // 10 | 2 | short | Icons Size (Options: 16, 32, 64) + + // Icons name id (32 bytes per name id) + // foreach (icon) + // { + // 12+32*i | 32 | char | Icon NameId + // } + + // Icons data: One bit per pixel, stored as unsigned int array (depends on icon size) + // Size*Size pixels/32bit per unsigned int = K unsigned int per icon + // foreach (icon) + // { + // ... | K | unsigned int | Icon Data + // } + // ------------------------------------------------------ + unsigned char *fileDataPtr = (unsigned char *)fileData; char **guiIconsName = NULL; @@ -4724,7 +5278,8 @@ char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool { if (loadIconsName) { - guiIconsName = (char **)RAYGUI_CALLOC(iconCount, sizeof(char *)); + // NOTE: Always allocating RAYGUI_ICON_MAX_ICONS names slots + guiIconsName = (char **)RAYGUI_CALLOC(RAYGUI_ICON_MAX_ICONS, sizeof(char *)); for (int i = 0; i < iconCount; i++) { guiIconsName[i] = (char *)RAYGUI_CALLOC(RAYGUI_ICON_MAX_NAME_LENGTH, sizeof(char)); @@ -4750,20 +5305,35 @@ char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool // Draw selected icon using rectangles pixel-by-pixel void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color) { - #define BIT_CHECK(a,b) ((a) & (1u<<(b))) - - for (int i = 0, y = 0; i < RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32; i++) + if ((guiIconFontOffsetY > 0) && (iconId < RAYGUI_ICON_MAX_FONT_BACKED)) { - for (int k = 0; k < 32; k++) - { - if (BIT_CHECK(guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i], k)) - { - #if !defined(RAYGUI_STANDALONE) - GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize, (float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color); - #endif - } + int maxIconsPerLine = guiFont.texture.width/(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + int x = iconId%maxIconsPerLine; + int y = iconId/maxIconsPerLine; - if ((k == 15) || (k == 31)) y++; + Rectangle srcRec = { (float)x*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + RAYGUI_ICON_FONT_ATLAS_PADDING, + guiIconFontOffsetY + (float)y*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + RAYGUI_ICON_FONT_ATLAS_PADDING, + RAYGUI_ICON_SIZE, RAYGUI_ICON_SIZE }; + Rectangle dstRec = { (float)posX, (float)posY, (float)pixelSize*RAYGUI_ICON_SIZE, (float)pixelSize*RAYGUI_ICON_SIZE }; + + DrawTexturePro(guiFont.texture, srcRec, dstRec, RAYGUI_CLITERAL(Vector2){ 0, 0 }, 0.0f, color); + } + else + { + #define BIT_CHECK(a,b) ((a) & (1u<<(b))) + + for (int i = 0, y = 0; i < RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32; i++) + { + for (int k = 0; k < 32; k++) + { + if (BIT_CHECK(guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i], k)) + { + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize, + (float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color); + } + + if ((k == 15) || (k == 31)) y++; + } } } } @@ -4774,28 +5344,56 @@ void GuiSetIconScale(int scale) if (scale >= 1) guiIconScale = scale; } -// Get text width considering gui style and icon size (if required) +// Get text width considering gui style and icon size (if required). +// For multi-line text (containing '\n'), returns the width of the widest line. int GuiGetTextWidth(const char *text) { - #if !defined(ICON_TEXT_PADDING) - #define ICON_TEXT_PADDING 4 - #endif + if (text == NULL) return 0; + + int maxWidth = 0; + const char *linePtr = text; + + while ((linePtr[0] != '\0') && ((linePtr - text) < MAX_LINE_BUFFER_SIZE)) + { + int lineWidth = GetLineWidth(linePtr); + if (lineWidth > maxWidth) maxWidth = lineWidth; + + // Skip to the next '\n' (or end of string/buffer) + while ((linePtr[0] != '\0') && (linePtr[0] != '\n') && ((linePtr - text) < MAX_LINE_BUFFER_SIZE)) + { + linePtr++; + } + // Advance past the '\n' delimiter to the start of the next line + if (linePtr[0] == '\n') linePtr++; + } + + return maxWidth; +} + +#endif // !RAYGUI_NO_ICONS + +//---------------------------------------------------------------------------------- +// Module Internal Functions Definition +//---------------------------------------------------------------------------------- +// Get text line width (stops at '\n' or '\0') +// NOTE: Considers icon marker '#NNN#' +static int GetLineWidth(const char *text) +{ +#if !defined(RAYGUI_ICON_TEXT_PADDING) + #define RAYGUI_ICON_TEXT_PADDING 4 +#endif Vector2 textSize = { 0 }; int textIconOffset = 0; if ((text != NULL) && (text[0] != '\0')) { + // Icon marker: '#' + 1..3 digits + '#' (matches GetTextIcon()) if (text[0] == '#') { - for (int i = 1; (i < 5) && (text[i] != '\0'); i++) - { - if (text[i] == '#') - { - textIconOffset = i; - break; - } - } + int pos = 1; + while ((pos < 4) && (text[pos] >= '0') && (text[pos] <= '9')) pos++; + if (text[pos] == '#') textIconOffset = pos + 1; } text += textIconOffset; @@ -4803,10 +5401,10 @@ int GuiGetTextWidth(const char *text) // Make sure guiFont is set, GuiGetStyle() initializes it lazynessly float fontSize = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); - // Custom MeasureText() implementation + // Custom MeasureText() implementation -- single line only if ((guiFont.texture.id > 0) && (text != NULL)) { - // Get size in bytes of text, considering end of line and line break + // Get size in bytes of the line, considering end of line and line break int size = 0; for (int i = 0; i < MAX_LINE_BUFFER_SIZE; i++) { @@ -4830,239 +5428,12 @@ int GuiGetTextWidth(const char *text) } } - if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + ICON_TEXT_PADDING); + if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + RAYGUI_ICON_TEXT_PADDING); } return (int)textSize.x; } -#endif // !RAYGUI_NO_ICONS - -//---------------------------------------------------------------------------------- -// Module Internal Functions Definition -//---------------------------------------------------------------------------------- -// Load style from memory -// WARNING: Binary files only -static void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize) -{ - unsigned char *fileDataPtr = (unsigned char *)fileData; - - char signature[5] = { 0 }; - short version = 0; - short reserved = 0; - int propertyCount = 0; - - memcpy(signature, fileDataPtr, 4); - memcpy(&version, fileDataPtr + 4, sizeof(short)); - memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short)); - memcpy(&propertyCount, fileDataPtr + 4 + 2 + 2, sizeof(int)); - fileDataPtr += 12; - - if ((signature[0] == 'r') && - (signature[1] == 'G') && - (signature[2] == 'S') && - (signature[3] == ' ')) - { - short controlId = 0; - short propertyId = 0; - unsigned int propertyValue = 0; - - for (int i = 0; i < propertyCount; i++) - { - memcpy(&controlId, fileDataPtr, sizeof(short)); - memcpy(&propertyId, fileDataPtr + 2, sizeof(short)); - memcpy(&propertyValue, fileDataPtr + 2 + 2, sizeof(unsigned int)); - fileDataPtr += 8; - - if (controlId == 0) // DEFAULT control - { - // If a DEFAULT property is loaded, it is propagated to all controls - // NOTE: All DEFAULT properties should be defined first in the file - GuiSetStyle(0, (int)propertyId, propertyValue); - - if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int j = 1; j < RAYGUI_MAX_CONTROLS; j++) GuiSetStyle(j, (int)propertyId, propertyValue); - } - else GuiSetStyle((int)controlId, (int)propertyId, propertyValue); - } - - // Font loading is highly dependant on raylib API to load font data and image - -#if !defined(RAYGUI_STANDALONE) - // Load custom font if available - int fontDataSize = 0; - memcpy(&fontDataSize, fileDataPtr, sizeof(int)); - fileDataPtr += 4; - - if (fontDataSize > 0) - { - Font font = { 0 }; - int fontType = 0; // 0-Normal, 1-SDF - - memcpy(&font.baseSize, fileDataPtr, sizeof(int)); - memcpy(&font.glyphCount, fileDataPtr + 4, sizeof(int)); - memcpy(&fontType, fileDataPtr + 4 + 4, sizeof(int)); - fileDataPtr += 12; - - // Load font white rectangle - Rectangle fontWhiteRec = { 0 }; - memcpy(&fontWhiteRec, fileDataPtr, sizeof(Rectangle)); - fileDataPtr += 16; - - // Load font image parameters - int fontImageUncompSize = 0; - int fontImageCompSize = 0; - memcpy(&fontImageUncompSize, fileDataPtr, sizeof(int)); - memcpy(&fontImageCompSize, fileDataPtr + 4, sizeof(int)); - fileDataPtr += 8; - - Image imFont = { 0 }; - imFont.mipmaps = 1; - memcpy(&imFont.width, fileDataPtr, sizeof(int)); - memcpy(&imFont.height, fileDataPtr + 4, sizeof(int)); - memcpy(&imFont.format, fileDataPtr + 4 + 4, sizeof(int)); - fileDataPtr += 12; - - if ((fontImageCompSize > 0) && (fontImageCompSize != fontImageUncompSize)) - { - // Compressed font atlas image data (DEFLATE), it requires DecompressData() - int dataUncompSize = 0; - unsigned char *compData = (unsigned char *)RAYGUI_CALLOC(fontImageCompSize, sizeof(unsigned char)); - memcpy(compData, fileDataPtr, fontImageCompSize); - fileDataPtr += fontImageCompSize; - - imFont.data = DecompressData(compData, fontImageCompSize, &dataUncompSize); - - // Security check, dataUncompSize must match the provided fontImageUncompSize - if (dataUncompSize != fontImageUncompSize) RAYGUI_LOG("WARNING: Uncompressed font atlas image data could be corrupted"); - - RAYGUI_FREE(compData); - } - else - { - // Font atlas image data is not compressed - imFont.data = (unsigned char *)RAYGUI_CALLOC(fontImageUncompSize, sizeof(unsigned char)); - memcpy(imFont.data, fileDataPtr, fontImageUncompSize); - fileDataPtr += fontImageUncompSize; - } - - if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture); - font.texture = LoadTextureFromImage(imFont); - - RAYGUI_FREE(imFont.data); - - // Validate font atlas texture was loaded correctly - if (font.texture.id != 0) - { - // Load font recs data - int recsDataSize = font.glyphCount*sizeof(Rectangle); - int recsDataCompressedSize = 0; - - // WARNING: Version 400 adds the compression size parameter - if (version >= 400) - { - // RGS files version 400 support compressed recs data - memcpy(&recsDataCompressedSize, fileDataPtr, sizeof(int)); - fileDataPtr += sizeof(int); - } - - if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize)) - { - // Recs data is compressed, uncompress it - unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_CALLOC(recsDataCompressedSize, sizeof(unsigned char)); - - memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize); - fileDataPtr += recsDataCompressedSize; - - int recsDataUncompSize = 0; - font.recs = (Rectangle *)DecompressData(recsDataCompressed, recsDataCompressedSize, &recsDataUncompSize); - - // Security check, data uncompressed size must match the expected original data size - if (recsDataUncompSize != recsDataSize) RAYGUI_LOG("WARNING: Uncompressed font recs data could be corrupted"); - - RAYGUI_FREE(recsDataCompressed); - } - else - { - // Recs data is uncompressed - font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle)); - for (int i = 0; i < font.glyphCount; i++) - { - memcpy(&font.recs[i], fileDataPtr, sizeof(Rectangle)); - fileDataPtr += sizeof(Rectangle); - } - } - - // Load font glyphs info data - int glyphsDataSize = font.glyphCount*16; // 16 bytes data per glyph - int glyphsDataCompressedSize = 0; - - // WARNING: Version 400 adds the compression size parameter - if (version >= 400) - { - // RGS files version 400 support compressed glyphs data - memcpy(&glyphsDataCompressedSize, fileDataPtr, sizeof(int)); - fileDataPtr += sizeof(int); - } - - // Allocate required glyphs space to fill with data - font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo)); - - if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize)) - { - // Glyphs data is compressed, uncompress it - unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_CALLOC(glyphsDataCompressedSize, sizeof(unsigned char)); - - memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize); - fileDataPtr += glyphsDataCompressedSize; - - int glyphsDataUncompSize = 0; - unsigned char *glyphsDataUncomp = DecompressData(glypsDataCompressed, glyphsDataCompressedSize, &glyphsDataUncompSize); - - // Security check, data uncompressed size must match the expected original data size - if (glyphsDataUncompSize != glyphsDataSize) RAYGUI_LOG("WARNING: Uncompressed font glyphs data could be corrupted"); - - unsigned char *glyphsDataUncompPtr = glyphsDataUncomp; - - for (int i = 0; i < font.glyphCount; i++) - { - memcpy(&font.glyphs[i].value, glyphsDataUncompPtr, sizeof(int)); - memcpy(&font.glyphs[i].offsetX, glyphsDataUncompPtr + 4, sizeof(int)); - memcpy(&font.glyphs[i].offsetY, glyphsDataUncompPtr + 8, sizeof(int)); - memcpy(&font.glyphs[i].advanceX, glyphsDataUncompPtr + 12, sizeof(int)); - glyphsDataUncompPtr += 16; - } - - RAYGUI_FREE(glypsDataCompressed); - RAYGUI_FREE(glyphsDataUncomp); - } - else - { - // Glyphs data is uncompressed - for (int i = 0; i < font.glyphCount; i++) - { - memcpy(&font.glyphs[i].value, fileDataPtr, sizeof(int)); - memcpy(&font.glyphs[i].offsetX, fileDataPtr + 4, sizeof(int)); - memcpy(&font.glyphs[i].offsetY, fileDataPtr + 8, sizeof(int)); - memcpy(&font.glyphs[i].advanceX, fileDataPtr + 12, sizeof(int)); - fileDataPtr += 16; - } - } - } - else font = GetFontDefault(); // Fallback in case of errors loading font atlas texture - - GuiSetFont(font); - - // Set font texture source rectangle to be used as white texture to draw shapes - // NOTE: It makes possible to draw shapes and text (full UI) in a single draw call - if ((fontWhiteRec.x > 0) && - (fontWhiteRec.y > 0) && - (fontWhiteRec.width > 0) && - (fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec); - } -#endif - } -} - // Get text bounds considering control bounds static Rectangle GetTextBounds(int control, Rectangle bounds) { @@ -5083,11 +5454,11 @@ static Rectangle GetTextBounds(int control, Rectangle bounds) case SLIDER: case CHECKBOX: case VALUEBOX: - case CONTROL11: - // TODO: More special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER + case TABBAR: + // TODO: Special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER default: { - // TODO: WARNING: TEXT_ALIGNMENT is already considered in GuiDrawText() + // WARNING: TEXT_ALIGNMENT is already considered in GuiDrawText() if (GuiGetStyle(control, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT) textBounds.x -= GuiGetStyle(control, TEXT_PADDING); else textBounds.x += GuiGetStyle(control, TEXT_PADDING); } @@ -5098,12 +5469,12 @@ static Rectangle GetTextBounds(int control, Rectangle bounds) } // Get text icon if provided and move text cursor -// NOTE: Up to #999# values supported for iconId +// NOTE: Up to RAYGUI_ICON_MAX_ICONS supported for iconId static const char *GetTextIcon(const char *text, int *iconId) { #if !defined(RAYGUI_NO_ICONS) *iconId = -1; - if (text[0] == '#') // Maybe it is stars with an icon, ending # must be found + if (text[0] == '#') // Maybe an icon, if it starts with # but an ending # must be found { char iconValue[4] = { 0 }; // Maximum length for icon value: 3 digits + '\0' @@ -5116,11 +5487,15 @@ static const char *GetTextIcon(const char *text, int *iconId) if (text[pos] == '#') { - *iconId = TextToInteger(iconValue); + int rawIconId = TextToInteger(iconValue); + if (rawIconId < RAYGUI_ICON_MAX_ICONS) + { + *iconId = rawIconId; - // Move text pointer after icon - // WARNING: If only icon provided, it could point to EOL character: '\0' - if (*iconId >= 0) text += (pos + 1); + // Move text pointer after icon + // WARNING: If only icon provided, it could point to EOL character: '\0' + if (*iconId >= 0) text += (pos + 1); + } } } #endif @@ -5188,8 +5563,8 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C { #define TEXT_VALIGN_PIXEL_OFFSET(h) ((int)h%2) // Vertical alignment for pixel perfect - #if !defined(ICON_TEXT_PADDING) - #define ICON_TEXT_PADDING 4 + #if !defined(RAYGUI_ICON_TEXT_PADDING) + #define RAYGUI_ICON_TEXT_PADDING 4 #endif if ((text == NULL) || (text[0] == '\0')) return; // Security check @@ -5225,9 +5600,9 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C Vector2 textBoundsPosition = { textBounds.x, textBounds.y }; float textBoundsWidthOffset = 0.0f; - // NOTE: Get text size after icon has been processed - // WARNING: GuiGetTextWidth() also processes text icon to get width! -> Really needed? - int textSizeX = GuiGetTextWidth(lines[i]); + // NOTE: Icon was already stripped above by GetTextIcon(); GetLineWidth() + // takes no icon path here and returns only the glyph width of this line. + int textSizeX = GetLineWidth(lines[i]); // If text requires an icon, add size to measure if (iconId >= 0) @@ -5236,7 +5611,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C // WARNING: If only icon provided, text could be pointing to EOF character: '\0' #if !defined(RAYGUI_NO_ICONS) - if ((lines[i] != NULL) && (lines[i][0] != '\0')) textSizeX += ICON_TEXT_PADDING; + if ((lines[i] != NULL) && (lines[i][0] != '\0')) textSizeX += RAYGUI_ICON_TEXT_PADDING; #endif } @@ -5273,12 +5648,11 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C { // NOTE: Considering icon height, probably different than text size GuiDrawIcon(iconId, (int)textBoundsPosition.x, (int)(textBounds.y + textBounds.height/2 - RAYGUI_ICON_SIZE*guiIconScale/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height)), guiIconScale, tint); - textBoundsPosition.x += (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); - textBoundsWidthOffset = (float)(RAYGUI_ICON_SIZE*guiIconScale + ICON_TEXT_PADDING); + textBoundsPosition.x += (float)(RAYGUI_ICON_SIZE*guiIconScale + RAYGUI_ICON_TEXT_PADDING); + textBoundsWidthOffset = (float)(RAYGUI_ICON_SIZE*guiIconScale + RAYGUI_ICON_TEXT_PADDING); } #endif - // Get size in bytes of text, - // considering end of line and line break + // Get size in bytes of text, considering end of line and line break int lineSize = 0; for (int c = 0; (lines[i][c] != '\0') && (lines[i][c] != '\n') && (lines[i][c] != '\r'); c++, lineSize++){ } float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize; @@ -5299,7 +5673,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C // NOTE: Normally, exiting the decoding sequence as soon as a bad byte is found (and return 0x3f) // but all of the bad bytes need to be drawn using the '?' symbol, moving one byte - if (codepoint == 0x3f) codepointSize = 1; // TODO: Review not recognized codepoints size + if (codepoint == 0x3f) codepointSize = 1; // WARNING: Not recognized codepoints size // Get glyph width to check if it goes out of bounds if (guiFont.glyphs[index].advanceX == 0) glyphWidth = ((float)guiFont.recs[index].width*scaleFactor); @@ -5315,7 +5689,7 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C textOffsetX = 0.0f; textOffsetY += (GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); - if (tempWrapCharMode) // Wrap at char level when too long words + if (tempWrapCharMode) // Wrap at char level when too long words { wrapMode = TEXT_WRAP_WORD; tempWrapCharMode = false; @@ -5346,12 +5720,12 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C } } - if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint + if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint else { - // TODO: There are multiple types of spaces in Unicode, + // WARNING: There are multiple types of spaces in Unicode, // maybe it's a good idea to add support for more: http://jkorpela.fi/chars/spaces.html - if ((codepoint != ' ') && (codepoint != '\t')) // Do not draw codepoints with no glyph + if ((codepoint != ' ') && (codepoint != '\t')) // Do not draw codepoints with no glyph { if (wrapMode == TEXT_WRAP_NONE) { @@ -5393,7 +5767,8 @@ static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, C } if (wrapMode == TEXT_WRAP_NONE) posOffsetY += (float)(GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); - else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) posOffsetY += (textOffsetY + (float)GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); + else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) + posOffsetY += (textOffsetY + GuiGetStyle(DEFAULT, TEXT_SIZE)); //--------------------------------------------------------------------------------- } @@ -5430,7 +5805,8 @@ static void GuiTooltip(Rectangle controlRec) { if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiControlExclusiveMode) { - Vector2 textSize = MeasureTextEx(GuiGetFont(), guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + Vector2 textSize = MeasureTextEx(guiFont, guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); if ((controlRec.x + textSize.x + 16) > GetScreenWidth()) controlRec.x -= (textSize.x + 16 - controlRec.width); @@ -5452,9 +5828,264 @@ static void GuiTooltip(Rectangle controlRec) } } +// Scroll bar control (used by GuiScrollPanel()) +static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) +{ + GuiState state = guiState; + + // Is the scrollbar horizontal or vertical? + bool isVertical = (bounds.width > bounds.height)? false : true; + + // The size (width or height depending on scrollbar type) of the spinner buttons + const int spinnerSize = GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)? + (isVertical? (int)bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) : + (int)bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0; + + // Arrow buttons [<] [>] [∧] [∨] + Rectangle arrowUpLeft = { 0 }; + Rectangle arrowDownRight = { 0 }; + + // Actual area of the scrollbar excluding the arrow buttons + Rectangle scrollbar = { 0 }; + + // Slider bar that moves --[///]----- + Rectangle slider = { 0 }; + + // Normalize value + if (value > maxValue) value = maxValue; + if (value < minValue) value = minValue; + + int valueRange = maxValue - minValue; + if (valueRange <= 0) valueRange = 1; + + int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); + if (sliderSize < 1) sliderSize = 1; // Consider a minimum slider size of 1 pixel + + // Calculate rectangles for all of the components + arrowUpLeft = RAYGUI_CLITERAL(Rectangle){ + (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), + (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), + (float)spinnerSize, (float)spinnerSize }; + + if (isVertical) + { + arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + bounds.height - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; + scrollbar = RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), arrowUpLeft.y + arrowUpLeft.height, bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)), bounds.height - arrowUpLeft.height - arrowDownRight.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) }; + + // Make sure the slider won't get outside of the scrollbar + sliderSize = (sliderSize >= scrollbar.height)? ((int)scrollbar.height - 2) : sliderSize; + slider = RAYGUI_CLITERAL(Rectangle){ + bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), + scrollbar.y + (int)(((float)(value - minValue)/valueRange)*(scrollbar.height - sliderSize)), + bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)), + (float)sliderSize }; + } + else // horizontal + { + arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; + scrollbar = RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x + arrowUpLeft.width, bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), bounds.width - arrowUpLeft.width - arrowDownRight.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)) }; + + // Make sure the slider won't get outside of the scrollbar + sliderSize = (sliderSize >= scrollbar.width)? ((int)scrollbar.width - 2) : sliderSize; + slider = RAYGUI_CLITERAL(Rectangle){ + scrollbar.x + (int)(((float)(value - minValue)/valueRange)*(scrollbar.width - sliderSize)), + bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), + (float)sliderSize, + bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)) }; + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (GUI_BUTTON_DOWN && + !CheckCollisionPointRec(mousePoint, arrowUpLeft) && + !CheckCollisionPointRec(mousePoint, arrowDownRight)) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + state = STATE_PRESSED; + + if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); + else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + + // Handle mouse wheel + float scrollDelta = GUI_SCROLL_DELTA; + if (scrollDelta != 0) value += (int)scrollDelta; + + // Handle mouse button down + if (GUI_BUTTON_PRESSED) + { + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + + // Check arrows click + if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + else if (!CheckCollisionPointRec(mousePoint, slider)) + { + // If click on scrollbar position but not on slider, place slider directly on that position + if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); + else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); + } + + state = STATE_PRESSED; + } + + // Keyboard control on mouse hover scrollbar + /* + if (isVertical) + { + if (GUI_KEY_DOWN(KEY_DOWN)) value += 5; + else if (GUI_KEY_DOWN(KEY_UP)) value -= 5; + } + else + { + if (GUI_KEY_DOWN(KEY_RIGHT)) value += 5; + else if (GUI_KEY_DOWN(KEY_LEFT)) value -= 5; + } + */ + } + + // Normalize value + if (value > maxValue) value = maxValue; + if (value < minValue) value = minValue; + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED))); // Draw the background + + GuiDrawRectangle(scrollbar, 0, BLANK, GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL))); // Draw the scrollbar active area background + GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BORDER + state*3))); // Draw the slider bar + + // Draw arrows (using icon if available) + if (GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)) + { +#if defined(RAYGUI_NO_ICONS) + GuiDrawText(isVertical? "^" : "<", + RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); + GuiDrawText(isVertical? "v" : ">", + RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); +#else + GuiDrawText(isVertical? GuiIconText(ICON_ARROW_UP_FILL, NULL) : GuiIconText(ICON_ARROW_LEFT_FILL, NULL), + RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_UP_FILL / ICON_ARROW_LEFT_FILL + GuiDrawText(isVertical? GuiIconText(ICON_ARROW_DOWN_FILL, NULL) : GuiIconText(ICON_ARROW_RIGHT_FILL, NULL), + RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_DOWN_FILL / ICON_ARROW_RIGHT_FILL +#endif + } + //-------------------------------------------------------------------- + + return value; +} + +// Update font image atlas to append raygui icons +static int GuiFontIconBaking(Image *imFont, Font font, Rectangle *whiteRec) +{ + int iconOffsetY = 0; + + // Check max glyph rec y bottom position in the atlas image, + // to start drawing icons below that line + int maxGlyphRecY = 0; + for (int i = 0; i < font.glyphCount; i++) + { + if ((font.recs[i].y + font.recs[i].height) > maxGlyphRecY) + maxGlyphRecY = (int)font.recs[i].y + (int)font.recs[i].height; + } + + int maxIconsPerLine = imFont->width/(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + int reqIconLines = RAYGUI_ICON_MAX_FONT_BACKED/maxIconsPerLine + RAYGUI_ICON_MAX_FONT_BACKED%maxIconsPerLine + 1; // One extra line + int reqHeight = reqIconLines*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + + // Check if image requires scaling and how much + if ((maxGlyphRecY + reqHeight) > imFont->height) + { + int newImHeight = 1; + while (newImHeight < (maxGlyphRecY + reqHeight)) newImHeight <<= 1; // Round to next POT + + char *newImData = (char *)RL_CALLOC(imFont->width*newImHeight*2, sizeof(char)); + memcpy(newImData, imFont->data, imFont->width*imFont->height*2); + RL_FREE(imFont->data); + + // Clear imFont bottom-right corner rec + for (int y = 0; y < 4; y++) + for (int x = 0; x < 4; x++) + ((unsigned short *)newImData)[(imFont->height - y - 1)*imFont->width + imFont->width - x - 1] = 0x0000; + + imFont->data = newImData; + imFont->height = newImHeight; + + // Set new image white corner and new white rec + for (int y = 0; y < 3; y++) + for (int x = 0; x < 3; x++) + ((unsigned short *)newImData)[(imFont->height - y - 1)*imFont->width + imFont->width - x - 1] = 0xffff; + + *whiteRec = RAYGUI_CLITERAL(Rectangle){ (float)imFont->width - 2, (float)imFont->height - 2, 1, 1 }; + } + + // Calculate image offset positions to start drawing + // NOTE: For Y, look for a multiple of icon size + 2*padding, for better alignment + int offsetX = RAYGUI_ICON_FONT_ATLAS_PADDING; + int offsetY = ((maxGlyphRecY + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING - 1))/ + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING))*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + + RAYGUI_ICON_FONT_ATLAS_PADDING; + + iconOffsetY = offsetY - RAYGUI_ICON_FONT_ATLAS_PADDING; + unsigned short *pixels = (unsigned short *)imFont->data; + + #define BIT_CHECK(a,b) ((a) & (1u<<(b))) + + for (int iconId = 0; iconId < RAYGUI_ICON_MAX_FONT_BACKED; iconId++) + { + // Wrap to next line if next icon won't fit + if ((offsetX + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING)) > imFont->width) + { + offsetX = RAYGUI_ICON_FONT_ATLAS_PADDING; + offsetY += RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING; + } + + for (int i = 0, y = 0; i < RAYGUI_ICON_DATA_ELEMENTS; i++) + { + unsigned int data = guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i]; + + for (int k = 0; k < 32; k++) + { + pixels[(offsetY + y)*imFont->width + offsetX + k%16] = (BIT_CHECK(data, k))? 0xffff : 0x00ff; + + if ((k == 15) || (k == 31)) y++; + } + } + + // Update current icon X position + offsetX += (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + } + + return iconOffsetY; +} + // Split controls text into multiple strings -// Also check for multiple columns (required by GuiToggleGroup()) -static char **GuiTextSplit(const char *text, char delimiter, int *count, int *textRow) +// NOTE: Re-used by GuiToggleSlider(), GuiComboBox(), GuiDropdownBox(), GuiListView(), GuiMessageBox(), GuiInputBox() +static char **GuiTextSplit(const char *text, char delimiter, int *count) { // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, @@ -5463,24 +6094,19 @@ static char **GuiTextSplit(const char *text, char delimiter, int *count, int *te // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE // NOTE: Those definitions could be externally provided if required - // TODO: HACK: GuiTextSplit() - Review how textRows are returned to user - // textRow is an externally provided array of integers that stores row number for every splitted string - #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS) #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128 #endif #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE) - #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 + #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 // WARNING: Max expected size for all concat items #endif - static char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL }; // String pointers array (points to buffer data) + static char *itemPtrs[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { 0 }; // String pointers array (points to buffer data) static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; // Buffer data (text input copy with '\0' added) memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE); - result[0] = buffer; - int counter = 1; - - if (textRow != NULL) textRow[0] = 0; + itemPtrs[0] = buffer; + int itemCounter = 1; // Count how many substrings text contains and point to every one of them for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++) @@ -5489,24 +6115,16 @@ static char **GuiTextSplit(const char *text, char delimiter, int *count, int *te if (buffer[i] == '\0') break; else if ((buffer[i] == delimiter) || (buffer[i] == '\n')) { - result[counter] = buffer + i + 1; + itemPtrs[itemCounter] = buffer + i + 1; + buffer[i] = '\0'; // Set terminator for current item - if (textRow != NULL) - { - if (buffer[i] == '\n') textRow[counter] = textRow[counter - 1] + 1; - else textRow[counter] = textRow[counter - 1]; - } - - buffer[i] = '\0'; // Set an end of string at this point - - counter++; - if (counter >= RAYGUI_TEXTSPLIT_MAX_ITEMS) break; + itemCounter++; + if (itemCounter >= RAYGUI_TEXTSPLIT_MAX_ITEMS) break; } } - *count = counter; - - return result; + *count = itemCounter; + return itemPtrs; } // Convert color data from RGB to HSV @@ -5633,179 +6251,9 @@ static Vector3 ConvertHSVtoRGB(Vector3 hsv) return rgb; } -// Scroll bar control (used by GuiScrollPanel()) -static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) -{ - GuiState state = guiState; - - // Is the scrollbar horizontal or vertical? - bool isVertical = (bounds.width > bounds.height)? false : true; - - // The size (width or height depending on scrollbar type) of the spinner buttons - const int spinnerSize = GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)? - (isVertical? (int)bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) : - (int)bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0; - - // Arrow buttons [<] [>] [∧] [∨] - Rectangle arrowUpLeft = { 0 }; - Rectangle arrowDownRight = { 0 }; - - // Actual area of the scrollbar excluding the arrow buttons - Rectangle scrollbar = { 0 }; - - // Slider bar that moves --[///]----- - Rectangle slider = { 0 }; - - // Normalize value - if (value > maxValue) value = maxValue; - if (value < minValue) value = minValue; - - int valueRange = maxValue - minValue; - if (valueRange <= 0) valueRange = 1; - - int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); - if (sliderSize < 1) sliderSize = 1; // TODO: Consider a minimum slider size - - // Calculate rectangles for all of the components - arrowUpLeft = RAYGUI_CLITERAL(Rectangle){ - (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), - (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), - (float)spinnerSize, (float)spinnerSize }; - - if (isVertical) - { - arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + bounds.height - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; - scrollbar = RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), arrowUpLeft.y + arrowUpLeft.height, bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)), bounds.height - arrowUpLeft.height - arrowDownRight.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) }; - - // Make sure the slider won't get outside of the scrollbar - sliderSize = (sliderSize >= scrollbar.height)? ((int)scrollbar.height - 2) : sliderSize; - slider = RAYGUI_CLITERAL(Rectangle){ - bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), - scrollbar.y + (int)(((float)(value - minValue)/valueRange)*(scrollbar.height - sliderSize)), - bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)), - (float)sliderSize }; - } - else // horizontal - { - arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; - scrollbar = RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x + arrowUpLeft.width, bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), bounds.width - arrowUpLeft.width - arrowDownRight.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)) }; - - // Make sure the slider won't get outside of the scrollbar - sliderSize = (sliderSize >= scrollbar.width)? ((int)scrollbar.width - 2) : sliderSize; - slider = RAYGUI_CLITERAL(Rectangle){ - scrollbar.x + (int)(((float)(value - minValue)/valueRange)*(scrollbar.width - sliderSize)), - bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), - (float)sliderSize, - bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)) }; - } - - // Update control - //-------------------------------------------------------------------- - if ((state != STATE_DISABLED) && !guiLocked) - { - Vector2 mousePoint = GUI_POINTER_POSITION; - - if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds - { - if (GUI_BUTTON_DOWN && - !CheckCollisionPointRec(mousePoint, arrowUpLeft) && - !CheckCollisionPointRec(mousePoint, arrowDownRight)) - { - if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) - { - state = STATE_PRESSED; - - if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); - else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); - } - } - else - { - guiControlExclusiveMode = false; - guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; - } - } - else if (CheckCollisionPointRec(mousePoint, bounds)) - { - state = STATE_FOCUSED; - - // Handle mouse wheel - float scrollDelta = GUI_SCROLL_DELTA; - if (scrollDelta != 0) value += (int)scrollDelta; - - // Handle mouse button down - if (GUI_BUTTON_PRESSED) - { - guiControlExclusiveMode = true; - guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts - - // Check arrows click - if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); - else if (!CheckCollisionPointRec(mousePoint, slider)) - { - // If click on scrollbar position but not on slider, place slider directly on that position - if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); - else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); - } - - state = STATE_PRESSED; - } - - // Keyboard control on mouse hover scrollbar - /* - if (isVertical) - { - if (GUI_KEY_DOWN(KEY_DOWN)) value += 5; - else if (GUI_KEY_DOWN(KEY_UP)) value -= 5; - } - else - { - if (GUI_KEY_DOWN(KEY_RIGHT)) value += 5; - else if (GUI_KEY_DOWN(KEY_LEFT)) value -= 5; - } - */ - } - - // Normalize value - if (value > maxValue) value = maxValue; - if (value < minValue) value = minValue; - } - //-------------------------------------------------------------------- - - // Draw control - //-------------------------------------------------------------------- - GuiDrawRectangle(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED))); // Draw the background - - GuiDrawRectangle(scrollbar, 0, BLANK, GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL))); // Draw the scrollbar active area background - GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BORDER + state*3))); // Draw the slider bar - - // Draw arrows (using icon if available) - if (GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)) - { -#if defined(RAYGUI_NO_ICONS) - GuiDrawText(isVertical? "^" : "<", - RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); - GuiDrawText(isVertical? "v" : ">", - RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); -#else - GuiDrawText(isVertical? "#121#" : "#118#", - RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_UP_FILL / ICON_ARROW_LEFT_FILL - GuiDrawText(isVertical? "#120#" : "#119#", - RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, - TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_DOWN_FILL / ICON_ARROW_RIGHT_FILL -#endif - } - //-------------------------------------------------------------------- - - return value; -} - // Color fade-in or fade-out, alpha goes from 0.0f to 1.0f -// WARNING: It multiplies current alpha by alpha scale factor +// WARNING: It multiplies current alpha by alpha scale factor, +// raylib Fade() multiplies alpha by 255.0f static Color GuiFade(Color color, float alpha) { if (alpha < 0.0f) alpha = 0.0f; @@ -5830,6 +6278,19 @@ static Color GetColor(int hexValue) return color; } +// Get color with alpha applied, alpha goes from 0.0f to 1.0f +static Color Fade(Color color, float alpha) +{ + Color result = color; + + if (alpha < 0.0f) alpha = 0.0f; + else if (alpha > 1.0f) alpha = 1.0f; + + result.a = (unsigned char)(255.0f*alpha); + + return result; +} + // Returns hexadecimal value for a Color static int ColorToInt(Color color) { @@ -5854,7 +6315,8 @@ static const char *TextFormat(const char *text, ...) #define RAYGUI_TEXTFORMAT_MAX_SIZE 256 #endif - static char buffer[RAYGUI_TEXTFORMAT_MAX_SIZE]; + static char buffer[RAYGUI_TEXTFORMAT_MAX_SIZE] = { 0 }; + memset(buffer, 0, RAYGUI_TEXTFORMAT_MAX_SIZE); va_list args; va_start(args, text); @@ -5864,61 +6326,6 @@ static const char *TextFormat(const char *text, ...) return buffer; } -// Draw rectangle with vertical gradient fill color -// NOTE: This function is only used by GuiColorPicker() -static void DrawRectangleGradientV(int posX, int posY, int width, int height, Color color1, Color color2) -{ - Rectangle bounds = { (float)posX, (float)posY, (float)width, (float)height }; - DrawRectangleGradientEx(bounds, color1, color2, color2, color1); -} - -// Split string into multiple strings -char **TextSplit(const char *text, char delimiter, int *count) -{ - // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) - // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, - // all used memory is static... it has some limitations: - // 1. Maximum number of possible split strings is set by RAYGUI_TEXTSPLIT_MAX_ITEMS - // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE - - #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS) - #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128 - #endif - #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE) - #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 - #endif - - static const char *result[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { NULL }; - static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; - memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE); - - result[0] = buffer; - int counter = 0; - - if (text != NULL) - { - counter = 1; - - // Count how many substrings text contains and point to every one of them - for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++) - { - buffer[i] = text[i]; - if (buffer[i] == '\0') break; - else if (buffer[i] == delimiter) - { - buffer[i] = '\0'; // Set an end of string at this point - result[counter] = buffer + i + 1; - counter++; - - if (counter == RAYGUI_TEXTSPLIT_MAX_ITEMS) break; - } - } - } - - *count = counter; - return result; -} - // Get integer value from text // NOTE: This function replaces atoi() [stdlib.h] static int TextToInteger(const char *text) diff --git a/examples/text/raygui.h b/examples/text/raygui.h new file mode 100644 index 000000000..f7a116150 --- /dev/null +++ b/examples/text/raygui.h @@ -0,0 +1,6460 @@ +/******************************************************************************************* +* +* raygui v5.0 - A simple and easy-to-use immediate-mode gui library +* +* DESCRIPTION: +* raygui is a tools-dev-focused immediate-mode-gui library based on raylib but also +* available as a standalone library, as long as input and drawing functions are provided +* +* FEATURES: +* - Immediate-mode gui, minimal retained data +* - +25 controls provided (basic and advanced) +* - Styling system for colors, font and metrics +* - Icons supported, embedded as a 1-bit icons pack +* - Standalone mode option (custom input/graphics backend) +* - Multiple support tools provided for raygui development +* +* POSSIBLE IMPROVEMENTS: +* - Better standalone mode API for easy plug of custom backends +* - Externalize required inputs, allow user easier customization +* +* LIMITATIONS: +* - No editable multi-line word-wraped text box supported +* - No auto-layout mechanism, up to the user to define controls position and size +* - Standalone mode requires library modification and some user work to plug another backend +* +* NOTES: +* - WARNING: GuiLoadStyle() and GuiLoadStyle{Custom}() functions, allocate memory for +* font atlas recs and glyphs, freeing that memory is (usually) up to the user, +* no unload function is explicitly provided... but note that GuiLoadStyleDefault() unloads +* by default any previously loaded font (texture, recs, glyphs) +* - Global UI alpha (guiAlpha) is applied inside GuiDrawRectangle() and GuiDrawText() functions +* +* CONTROLS PROVIDED: +* # Container/separators Controls +* - WindowBox --> StatusBar, Panel +* - GroupBox --> Line +* - Line +* - Panel --> StatusBar +* - ScrollPanel --> StatusBar +* - TabBar --> Toggle, Button +* +* # Basic Controls +* - Label +* - LabelButton --> Label +* - Button +* - Toggle +* - ToggleGroup --> Toggle +* - ToggleSlider +* - CheckBox +* - ComboBox +* - DropdownBox +* - TextBox +* - ValueBox --> TextBox +* - Spinner --> Button, ValueBox +* - Slider +* - SliderBar --> Slider +* - ProgressBar +* - StatusBar +* - DummyRec +* - Grid +* +* # Advance Controls +* - ListView +* - ColorPicker --> ColorPanel, ColorBarHue +* - MessageBox --> Window, Label, Button +* - TextInputBox --> Window, Label, TextBox, Button +* +* It also provides a set of functions for styling the controls based on its properties (size, color) +* +* +* RAYGUI STYLE (guiStyle): +* raygui uses a global data array for all gui style properties (allocated on data segment by default), +* when a new style is loaded, it is loaded over the global style... but a default gui style could always be +* recovered with GuiLoadStyleDefault() function, that overwrites the current style to the default one +* +* The global style array size is fixed and depends on the number of controls and properties: +* +* static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)]; +* +* guiStyle size is by default: 16*(16 + 8) = 384 int = 384*4 bytes = 1536 bytes = 1.5 KB +* +* Note that the first set of BASE properties (by default guiStyle[0..15]) belong to the generic style +* used for all controls, when any of those base values is set, it is automatically populated to all +* controls, so, specific control values overwriting generic style should be set after base values +* +* After the first BASE properties set, the EXTENDED properties set is defined (by default guiStyle[16..23]), +* those properties are actually common to all controls and can not be overwritten individually (like BASE ones) +* Some of those properties are: TEXT_SIZE, TEXT_SPACING, LINE_COLOR, BACKGROUND_COLOR +* +* Custom control properties can be defined using the EXTENDED properties for each independent control. +* +* TOOL: rGuiStyler is a visual tool to customize raygui style: github.com/raysan5/rguistyler +* +* +* RAYGUI ICONS (guiIcons): +* raygui could use a global array containing icons data (allocated on data segment by default), +* a custom icons set could be loaded over this array using GuiLoadIcons(), but loaded icons set +* must be same RAYGUI_ICON_SIZE and no more than RAYGUI_ICON_MAX_ICONS will be loaded +* +* Every icon is codified in binary form, using 1 bit per pixel, so, every 16x16 icon +* requires 8 integers (16*16/32) to be stored in memory. +* +* When the icon is draw, actually one quad per pixel is drawn if the bit for that pixel is set +* +* The global icons array size is fixed and depends on the number of icons and size: +* +* static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS]; +* +* guiIcons size is by default: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 KB +* +* TOOL: rGuiIcons is a visual tool to customize/create raygui icons: github.com/raysan5/rguiicons +* +* RAYGUI LAYOUT: +* raygui currently does not provide an auto-layout mechanism like other libraries, +* layouts must be defined manually on controls drawing, providing the right bounds Rectangle for it +* +* TOOL: rGuiLayout is a visual tool to create raygui layouts: github.com/raysan5/rguilayout +* +* CONFIGURATION: +* #define RAYGUI_IMPLEMENTATION +* Generates the implementation of the library into the included file +* If not defined, the library is in header only mode and can be included in other headers +* or source files without problems. But only ONE file should hold the implementation +* +* #define RAYGUI_STANDALONE +* Avoid raylib.h header inclusion in this file. Data types defined on raylib are defined +* internally in the library and input management and drawing functions must be provided by +* the user (check library implementation for further details) +* +* #define RAYGUI_NO_ICONS +* Avoid including embedded ricons data (256 icons, 16x16 pixels, 1-bit per pixel, 2KB) +* +* #define RAYGUI_CUSTOM_ICONS +* Includes custom ricons.h header defining a set of custom icons, +* this file can be generated using rGuiIcons tool +* +* #define RAYGUI_FONT_ICONS_BAKING +* On gui font loading from style file, append the icons to font atlas image, so, +* icons can be drawn along the text as a texture, instead of using shapes to draw them +* +* #define RAYGUI_DEBUG_RECS_BOUNDS +* Draw control bounds rectangles for debug +* +* #define RAYGUI_DEBUG_TEXT_BOUNDS +* Draw text bounds rectangles for debug +* +* VERSIONS HISTORY: +* 5.0 (20-Jul-2026) ADDED: NEW control: GuiTabBar() +* ADDED: Support up to 512 icons (v500) +* ADDED: Support icons baking into font atlas image +* ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes +* ADDED: GuiValueBoxFloat(), with floats support +* ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP +* ADDED: GuiListView() property: LIST_ITEMS_BORDER_WIDTH +* ADDED: GuiLoadIconsFromMemory(), used by GuiLoadIcons() +* ADDED: Macros for inputs customization, raylib decoupling +* ADDED: Control result return values: 1-RESULT_PRESSED, 2-RESULT_CHANGED, >2-Control_custom +* REMOVED: GuiSpinner() from controls list, using BUTTON + VALUEBOX properties +* REMOVED: GuiSliderPro(), functionality was redundant +* REMOVED: TextSplit() raylib function requirement on RAYGUI_STANDALONE +* REDESIGNED: WARNING: GuiLoadStyleFromMemory() to support icons baking into font atlas +* REDESIGNED: GuiToggleGroup() to process rows/cols with no need for GuiTextSplit() +* REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion +* REDESIGNED: WARNING: TEXT_LINE_SPACING does not consider text height, only lines spacing +* REDESIGNED: WARNING: GuiMessageBox(), added parameter for btn return, unify result +* REDESIGNED: WARNING: GuiTextInputBox(), added parameter for btn return, unify result +* REVIEWED: GuiLoadIconsFromMemory(), fixed memory issues +* REVIEWED: Controls using text labels to use LABEL properties +* REVIEWED: Replaced sprintf() by snprintf() for more safety +* REVIEWED: GuiTabBar(), close tab with mouse middle button +* REVIEWED: GuiScrollPanel(), scroll speed proportional to content +* REVIEWED: GuiDropdownBox(), support roll up and hidden arrow +* REVIEWED: GuiTextBox(), cursor position initialization +* REVIEWED: GuiSliderPro(), control value change check +* REVIEWED: GuiGrid(), simplified implementation +* REVIEWED: GuiIconText(), increase buffer size and reviewed padding +* REVIEWED: GuiDrawText(), improved wrap mode drawing +* REVIEWED: GuiScrollBar(), minor tweaks +* REVIEWED: GuiProgressBar(), improved borders computing +* REVIEWED: GuiTextBox(), multiple improvements: autocursor and more +* REVIEWED: Functions descriptions, removed wrong return value reference +* +* 4.0 (12-Sep-2023) ADDED: GuiToggleSlider() +* ADDED: GuiColorPickerHSV() and GuiColorPanelHSV() +* ADDED: Multiple new icons, mostly compiler related +* ADDED: New DEFAULT properties: TEXT_LINE_SPACING, TEXT_ALIGNMENT_VERTICAL, TEXT_WRAP_MODE +* ADDED: New enum values: GuiTextAlignment, GuiTextAlignmentVertical, GuiTextWrapMode +* ADDED: Support loading styles with custom font charset from external file +* REDESIGNED: GuiTextBox(), support mouse cursor positioning +* REDESIGNED: GuiDrawText(), support multiline and word-wrap modes (read only) +* REDESIGNED: GuiProgressBar() to be more visual, progress affects border color +* REDESIGNED: Global alpha consideration moved to GuiDrawRectangle() and GuiDrawText() +* REDESIGNED: GuiScrollPanel(), get parameters by reference and return result value +* REDESIGNED: GuiToggleGroup(), get parameters by reference and return result value +* REDESIGNED: GuiComboBox(), get parameters by reference and return result value +* REDESIGNED: GuiCheckBox(), get parameters by reference and return result value +* REDESIGNED: GuiSlider(), get parameters by reference and return result value +* REDESIGNED: GuiSliderBar(), get parameters by reference and return result value +* REDESIGNED: GuiProgressBar(), get parameters by reference and return result value +* REDESIGNED: GuiListView(), get parameters by reference and return result value +* REDESIGNED: GuiColorPicker(), get parameters by reference and return result value +* REDESIGNED: GuiColorPanel(), get parameters by reference and return result value +* REDESIGNED: GuiColorBarAlpha(), get parameters by reference and return result value +* REDESIGNED: GuiColorBarHue(), get parameters by reference and return result value +* REDESIGNED: GuiGrid(), get parameters by reference and return result value +* REDESIGNED: GuiGrid(), added extra parameter +* REDESIGNED: GuiListViewEx(), change parameters order +* REDESIGNED: All controls return result as int value +* REVIEWED: GuiScrollPanel() to avoid smallish scroll-bars +* REVIEWED: All examples and specially controls_test_suite +* RENAMED: gui_file_dialog module to gui_window_file_dialog +* UPDATED: All styles to include ISO-8859-15 charset (as much as possible) +* +* 3.6 (10-May-2023) ADDED: New icon: SAND_TIMER +* ADDED: GuiLoadStyleFromMemory() (binary only) +* REVIEWED: GuiScrollBar() horizontal movement key +* REVIEWED: GuiTextBox() crash on cursor movement +* REVIEWED: GuiTextBox(), additional inputs support +* REVIEWED: GuiLabelButton(), avoid text cut +* REVIEWED: GuiTextInputBox(), password input +* REVIEWED: Local GetCodepointNext(), aligned with raylib +* REDESIGNED: GuiSlider*()/GuiScrollBar() to support out-of-bounds +* +* 3.5 (20-Apr-2023) ADDED: GuiTabBar(), based on GuiToggle() +* ADDED: Helper functions to split text in separate lines +* ADDED: Multiple new icons, useful for code editing tools +* REMOVED: Unneeded icon editing functions +* REMOVED: GuiTextBoxMulti(), very limited and broken +* REMOVED: MeasureTextEx() dependency, logic directly implemented +* REMOVED: DrawTextEx() dependency, logic directly implemented +* REVIEWED: GuiScrollBar(), improve mouse-click behaviour +* REVIEWED: Library header info, more info, better organized +* REDESIGNED: GuiTextBox() to support cursor movement +* REDESIGNED: GuiDrawText() to divide drawing by lines +* +* 3.2 (22-May-2022) RENAMED: Some enum values, for unification, avoiding prefixes +* REMOVED: GuiScrollBar(), only internal +* REDESIGNED: GuiPanel() to support text parameter +* REDESIGNED: GuiScrollPanel() to support text parameter +* REDESIGNED: GuiColorPicker() to support text parameter +* REDESIGNED: GuiColorPanel() to support text parameter +* REDESIGNED: GuiColorBarAlpha() to support text parameter +* REDESIGNED: GuiColorBarHue() to support text parameter +* REDESIGNED: GuiTextInputBox() to support password +* +* 3.1 (12-Jan-2022) REVIEWED: Default style for consistency (aligned with rGuiLayout v2.5 tool) +* REVIEWED: GuiLoadStyle() to support compressed font atlas image data and unload previous textures +* REVIEWED: External icons usage logic +* REVIEWED: GuiLine() for centered alignment when including text +* RENAMED: Multiple controls properties definitions to prepend RAYGUI_ +* RENAMED: RICON_ references to RAYGUI_ICON_ for library consistency +* Projects updated and multiple tweaks +* +* 3.0 (04-Nov-2021) Integrated ricons data to avoid external file +* REDESIGNED: GuiTextBoxMulti() +* REMOVED: GuiImageButton*() +* Multiple minor tweaks and bugs corrected +* +* 2.9 (17-Mar-2021) REMOVED: Tooltip API +* 2.8 (03-May-2020) Centralized rectangles drawing to GuiDrawRectangle() +* 2.7 (20-Feb-2020) ADDED: Possible tooltips API +* 2.6 (09-Sep-2019) ADDED: GuiTextInputBox() +* REDESIGNED: GuiListView*(), GuiDropdownBox(), GuiSlider*(), GuiProgressBar(), GuiMessageBox() +* REVIEWED: GuiTextBox(), GuiSpinner(), GuiValueBox(), GuiLoadStyle() +* Replaced property INNER_PADDING by TEXT_PADDING, renamed some properties +* ADDED: 8 new custom styles ready to use +* Multiple minor tweaks and bugs corrected +* +* 2.5 (28-May-2019) Implemented extended GuiTextBox(), GuiValueBox(), GuiSpinner() +* 2.3 (29-Apr-2019) ADDED: rIcons auxiliar library and support for it, multiple controls reviewed +* Refactor all controls drawing mechanism to use control state +* 2.2 (05-Feb-2019) ADDED: GuiScrollBar(), GuiScrollPanel(), reviewed GuiListView(), removed Gui*Ex() controls +* 2.1 (26-Dec-2018) REDESIGNED: GuiCheckBox(), GuiComboBox(), GuiDropdownBox(), GuiToggleGroup() > Use combined text string +* REDESIGNED: Style system (breaking change) +* 2.0 (08-Nov-2018) ADDED: Support controls guiLock and custom fonts +* REVIEWED: GuiComboBox(), GuiListView()... +* 1.9 (09-Oct-2018) REVIEWED: GuiGrid(), GuiTextBox(), GuiTextBoxMulti(), GuiValueBox()... +* 1.8 (01-May-2018) Lot of rework and redesign to align with rGuiStyler and rGuiLayout +* 1.5 (21-Jun-2017) Working in an improved styles system +* 1.4 (15-Jun-2017) Rewritten all GUI functions (removed useless ones) +* 1.3 (12-Jun-2017) Complete redesign of style system +* 1.1 (01-Jun-2017) Complete review of the library +* 1.0 (07-Jun-2016) Converted to header-only by Ramon Santamaria +* 0.9 (07-Mar-2016) Reviewed and tested by Albert Martos, Ian Eito, Sergio Martinez and Ramon Santamaria +* 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria +* +* DEPENDENCIES: +* raylib 6.1-dev - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing +* +* STANDALONE MODE: +* By default raygui depends on raylib mostly for the inputs and the drawing functionality but that dependency can be disabled +* with the config flag RAYGUI_STANDALONE. In that case is up to the user to provide another backend to cover library needs +* +* The following functions should be redefined for a custom backend: +* +* - Vector2 GetMousePosition(void); +* - float GetMouseWheelMove(void); +* - bool IsMouseButtonDown(int button); +* - bool IsMouseButtonPressed(int button); +* - bool IsMouseButtonReleased(int button); +* - bool IsKeyDown(int key); +* - bool IsKeyPressed(int key); +* - int GetCharPressed(void); // -- GuiTextBox(), GuiValueBox() +* +* - void DrawRectangle(int x, int y, int width, int height, Color color); // -- GuiDrawRectangle() +* - void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // -- GuiColorPicker() +* +* - Font GetFontDefault(void); // -- GuiLoadStyleDefault() +* - Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // -- GuiLoadStyle() +* - Texture2D LoadTextureFromImage(Image image); // -- GuiLoadStyle(), required to load texture from embedded font atlas image +* - void SetShapesTexture(Texture2D tex, Rectangle rec); // -- GuiLoadStyle(), required to set shapes rec to font white rec (optimization) +* - char *LoadFileText(const char *fileName); // -- GuiLoadStyle(), required to load charset data +* - void UnloadFileText(char *text); // -- GuiLoadStyle(), required to unload charset data +* - const char *GetDirectoryPath(const char *filePath); // -- GuiLoadStyle(), required to find charset/font file from text .rgs +* - int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle(), required to load required font codepoints list +* - void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list +* - unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle() +* +* CONTRIBUTORS: +* Ramon Santamaria: Supervision, review, redesign, update and maintenance +* Vlad Adrian: Complete rewrite of GuiTextBox() to support extended features (2019) +* Sergio Martinez: Review, testing (2015) and redesign of multiple controls (2018) +* Adria Arranz: Testing and implementation of additional controls (2018) +* Jordi Jorba: Testing and implementation of additional controls (2018) +* Albert Martos: Review and testing of the library (2015) +* Ian Eito: Review and testing of the library (2015) +* Kevin Gato: Initial implementation of basic components (2014) +* Daniel Nicolas: Initial implementation of basic components (2014) +* +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2014-2026 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#ifndef RAYGUI_H +#define RAYGUI_H + +#define RAYGUI_VERSION_MAJOR 5 +#define RAYGUI_VERSION_MINOR 0 +#define RAYGUI_VERSION_PATCH 0 +#define RAYGUI_VERSION "5.0" + +#if !defined(RAYGUI_STANDALONE) + #include "raylib.h" +#endif + +// Function specifiers in case library is build/used as a shared library (Windows) +// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll +#if defined(_WIN32) + #if defined(BUILD_LIBTYPE_SHARED) + #define RAYGUIAPI __declspec(dllexport) // Building the library as a Win32 shared library (.dll) + #elif defined(USE_LIBTYPE_SHARED) + #define RAYGUIAPI __declspec(dllimport) // Using the library as a Win32 shared library (.dll) + #endif + #if !defined(_CRT_SECURE_NO_WARNINGS) + #define _CRT_SECURE_NO_WARNINGS // Disable unsafe warnings on scanf() functions in MSVC + #endif +#else + #if defined(BUILD_LIBTYPE_SHARED) + #define RAYGUIAPI __attribute__((visibility("default"))) // Building as a Unix shared library (.so/.dylib) + #endif +#endif + +// Function specifiers definition +#ifndef RAYGUIAPI + #define RAYGUIAPI // Functions defined as 'extern' by default (implicit specifiers) +#endif + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +// Simple log system to avoid printf() calls if required +// NOTE: Avoiding those calls, also avoids const strings memory usage +#define RAYGUI_SUPPORT_LOG_INFO +#if defined(RAYGUI_SUPPORT_LOG_INFO) + #define RAYGUI_LOG(...) printf(__VA_ARGS__) +#else + #define RAYGUI_LOG(...) +#endif + +#if !defined(RAYGUI_STANDALONE) +// Macros to define required UI inputs, including mapping to gamepad controls +#if !defined(GUI_BUTTON_DOWN) + #define GUI_BUTTON_DOWN (IsMouseButtonDown(MOUSE_LEFT_BUTTON) || IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) +#endif +#if !defined(GUI_BUTTON_DOWN_ALT) + // Mapping to alternative button down pressed + #define GUI_BUTTON_DOWN_ALT (IsMouseButtonDown(MOUSE_RIGHT_BUTTON) || IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_FACE_RIGHT)) +#endif +#if !defined(GUI_BUTTON_PRESSED) + #define GUI_BUTTON_PRESSED (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsGamepadButtonPressed(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) +#endif +#if !defined(GUI_BUTTON_PRESSED_MID) + #define GUI_BUTTON_PRESSED_MID (IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON) || IsGamepadButtonPressed(0, GAMEPAD_BUTTON_RIGHT_FACE_UP)) +#endif +#if !defined(GUI_BUTTON_RELEASED) + #define GUI_BUTTON_RELEASED (IsMouseButtonReleased(MOUSE_LEFT_BUTTON) || IsGamepadButtonReleased(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) +#endif +#if !defined(GUI_SCROLL_DELTA) + // Mapping to scroll delta changes + // TODO: Review mouse scroll inconsistencies between platforms + #if defined(PLATFORM_WEB) + // NOTE: Gamepad axis triggers not detected on web platform + #define GUI_SCROLL_DELTA ((float)IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_TRIGGER_2) - (float)IsGamepadButtonDown(0, GAMEPAD_BUTTON_LEFT_TRIGGER_2)) + #else + #define GUI_SCROLL_DELTA (GetMouseWheelMove() + (GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_TRIGGER) + 1) - (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_TRIGGER) + 1)) + #endif +#endif +#if !defined(GUI_POINTER_POSITION) + #define GUI_POINTER_POSITION GetMousePosition() +#endif +#if !defined(GUI_KEY_DOWN) + #define GUI_KEY_DOWN(key) IsKeyDown(key) +#endif +#if !defined(GUI_KEY_PRESSED) + #define GUI_KEY_PRESSED(key) IsKeyPressed(key) +#endif +#if !defined(GUI_INPUT_KEY) + #define GUI_INPUT_KEY GetCharPressed() +#endif +#else + #define GUI_BUTTON_DOWN 0 + #define GUI_BUTTON_DOWN_ALT 0 + #define GUI_BUTTON_PRESSED 0 + #define GUI_BUTTON_PRESSED_MID 0 + #define GUI_BUTTON_RELEASED 0 + #define GUI_SCROLL_DELTA 0 + #define GUI_POINTER_POSITION (Vector2){ 0 } + #define GUI_KEY_DOWN(key) 0 + #define GUI_KEY_PRESSED(key) 0 + #define GUI_INPUT_KEY 0 +#endif + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +// NOTE: Some types are required for RAYGUI_STANDALONE usage +//---------------------------------------------------------------------------------- +#if defined(RAYGUI_STANDALONE) + #ifndef __cplusplus + // Boolean type + #ifndef true + typedef enum { false, true } bool; + #endif + #endif + + // Vector2 type + typedef struct Vector2 { + float x; + float y; + } Vector2; + + // Vector3 type // -- ConvertHSVtoRGB(), ConvertRGBtoHSV() + typedef struct Vector3 { + float x; + float y; + float z; + } Vector3; + + // Color type, RGBA (32bit) + typedef struct Color { + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a; + } Color; + +#define BLANK (Color){ 0, 0, 0, 0 } // Blank (Transparent) + + // Rectangle type + typedef struct Rectangle { + float x; + float y; + float width; + float height; + } Rectangle; + + // NOTE: Texture2D type is very coupled to raylib, required by Font type + // It should be redesigned to be provided by user + typedef struct Texture { + unsigned int id; // OpenGL texture id + int width; // Texture base width + int height; // Texture base height + int mipmaps; // Mipmap levels, 1 by default + int format; // Data format (PixelFormat type) + } Texture; + + // Texture2D, same as Texture + typedef Texture Texture2D; + + // Image, pixel data stored in CPU memory (RAM) + typedef struct Image { + void *data; // Image raw data + int width; // Image base width + int height; // Image base height + int mipmaps; // Mipmap levels, 1 by default + int format; // Data format (PixelFormat type) + } Image; + + // GlyphInfo, font characters glyphs info + typedef struct GlyphInfo { + int value; // Character value (Unicode) + int offsetX; // Character offset X when drawing + int offsetY; // Character offset Y when drawing + int advanceX; // Character advance position X + Image image; // Character image data + } GlyphInfo; + + // NOTE: Font type is very coupled to raylib, mostly required by GuiLoadStyle() + // It should be redesigned to be provided by user + typedef struct Font { + int baseSize; // Base size (default chars height) + int glyphCount; // Number of glyph characters + int glyphPadding; // Padding around the glyph characters + Texture2D texture; // Texture atlas containing the glyphs + Rectangle *recs; // Rectangles in texture for the glyphs + GlyphInfo *glyphs; // Glyphs info data + } Font; +#endif + +// Style property +// NOTE: Used when exporting style as code for convenience +typedef struct GuiStyleProp { + unsigned short controlId; // Control identifier + unsigned short propertyId; // Property identifier + int propertyValue; // Property value +} GuiStyleProp; + +/* +// Controls text style -NOT USED- +// NOTE: Text style is defined by control +typedef struct GuiTextStyle { + unsigned int size; + int charSpacing; + int lineSpacing; + int alignmentH; + int alignmentV; + int padding; +} GuiTextStyle; +*/ + +// Gui control result +typedef enum { + RESULT_NONE = 0, + RESULT_PRESSED = 1, + RESULT_CHANGED = 2, + + RESULT_TAB_CLOSE = 4 // GuiTabBar(), tab close request +} GuiResult; + +// Gui control state +typedef enum { + STATE_NORMAL = 0, + STATE_FOCUSED, + STATE_PRESSED, + STATE_DISABLED +} GuiState; + +// Gui control text alignment +typedef enum { + TEXT_ALIGN_LEFT = 0, + TEXT_ALIGN_CENTER, + TEXT_ALIGN_RIGHT +} GuiTextAlignment; + +// Gui control text alignment vertical +// NOTE: Text vertical position inside the text bounds +typedef enum { + TEXT_ALIGN_TOP = 0, + TEXT_ALIGN_MIDDLE, + TEXT_ALIGN_BOTTOM +} GuiTextAlignmentVertical; + +// Gui control text wrap mode +// NOTE: Useful for multiline text +typedef enum { + TEXT_WRAP_NONE = 0, + TEXT_WRAP_CHAR, + TEXT_WRAP_WORD +} GuiTextWrapMode; + +// Gui controls +// NOTE: Up to 16 controls supported or 32 controls (v500) +typedef enum { + // Default -> populates to all controls when set + DEFAULT = 0, + + // Basic controls + LABEL = 1, // Used also for: LABELBUTTON + BUTTON = 2, + TOGGLE = 3, // Used also for: TOGGLEGROUP + SLIDER = 4, // Used also for: SLIDERBAR, TOGGLESLIDER + PROGRESSBAR = 5, + CHECKBOX = 6, + COMBOBOX = 7, + DROPDOWNBOX = 8, + TEXTBOX = 9, // Used also for: TEXTBOXMULTI + VALUEBOX = 10, + TABBAR = 11, + LISTVIEW = 12, + COLORPICKER = 13, + SCROLLBAR = 14, + STATUSBAR = 15 + // NOTE: More controls can be added if required +} GuiControl; + +// Controls BASE properties for every control (RAYGUI_MAX_PROPS_BASE = 16) +// NOTE: Properties required for all controls, DEFAULT control sets +// default values for them but they can be overriden per control +typedef enum { + BORDER_COLOR_NORMAL = 0, // Control border color in STATE_NORMAL + BASE_COLOR_NORMAL = 1, // Control base color in STATE_NORMAL + TEXT_COLOR_NORMAL = 2, // Control text color in STATE_NORMAL + BORDER_COLOR_FOCUSED = 3, // Control border color in STATE_FOCUSED + BASE_COLOR_FOCUSED = 4, // Control base color in STATE_FOCUSED + TEXT_COLOR_FOCUSED = 5, // Control text color in STATE_FOCUSED + BORDER_COLOR_PRESSED = 6, // Control border color in STATE_PRESSED + BASE_COLOR_PRESSED = 7, // Control base color in STATE_PRESSED + TEXT_COLOR_PRESSED = 8, // Control text color in STATE_PRESSED + BORDER_COLOR_DISABLED = 9, // Control border color in STATE_DISABLED + BASE_COLOR_DISABLED = 10, // Control base color in STATE_DISABLED + TEXT_COLOR_DISABLED = 11, // Control text color in STATE_DISABLED + BORDER_WIDTH = 12, // Control border size, 0 for no border + TEXT_PADDING = 13, // Control text padding, not considering border + TEXT_ALIGNMENT = 14, // Control text horizontal alignment inside control text bound (after border and padding): 0-Left, 1-Center, 2-Right + BASEPROP16 = 15 // Not used yet... +} GuiControlProperty; + + +// WARNING: Some properties have been chosen to be global with DEFAULT - EXTENDED properties: +// - TEXT_SIZE, // Control text size (glyphs max height) +// - TEXT_SPACING, // Control text spacing between glyphs +// - TEXT_LINE_SPACING, // Control text spacing between lines +// - TEXT_WRAP_MODE // Control text wrap-mode inside text bounds +// +// While other properties can be setup per globally (DEFAULT) or per control: +// - TEXT_PADDING // Control text padding, not considering border +// - TEXT_ALIGNMENT // Control text horizontal alignment inside control text bound + + +// Controls EXTENDED properties (RAYGUI_MAX_PROPS_EXTENDED = 8) +// WARNING: Only 8 slots vailable for those properties per control, including DEFAULT +//---------------------------------------------------------------------------------- +// DEFAULT control, extended properties +// NOTE: Those properties are global for all controls, they can not be setup per control +typedef enum { + TEXT_SIZE = 16, // Text size (glyphs max height) + TEXT_SPACING = 17, // Text spacing between glyphs + LINE_COLOR = 18, // Line control color + BACKGROUND_COLOR = 19, // Background color + TEXT_LINE_SPACING = 20, // Text spacing between lines + TEXT_ALIGNMENT_VERTICAL = 21, // Text vertical alignment inside text bounds (after border and padding): 0-Top, 1-Middle, 2-Bottom + TEXT_WRAP_MODE = 22, // Text wrap-mode inside text bounds + EXTPROP08 = 23 // Not used yet... +} GuiDefaultProperty; + +// Other possible text extended properties: +// TEXT_DECORATION // Text decoration: 0-None, 1-Underline, 2-Line-through, 3-Overline +// TEXT_DECORATION_THICK // Text decoration line thickness +// TEXT_FONT_WEIGHT // Text font weight: 0-Normal, 1-Bold, 2-Italic -> Requires specific font change + +// Label +//typedef enum { } GuiLabelProperty; + +// Button +//typedef enum { } GuiButtonProperty; + +// Toggle/ToggleGroup +typedef enum { + GROUP_PADDING = 16, // ToggleGroup separation between toggles + GROUP_WIDTH_FULL // ToggleGroup bounds width considers all items: 0-Width per item, 1-Full width +} GuiToggleProperty; + +// Slider/SliderBar +typedef enum { + SLIDER_WIDTH = 16, // Slider size of internal bar + SLIDER_PADDING // Slider/SliderBar internal bar padding +} GuiSliderProperty; + +// ProgressBar +typedef enum { + PROGRESS_PADDING = 16, // ProgressBar internal padding + PROGRESS_SIDE, // ProgressBar increment side: 0-Left->Right, 1-Right->Left +} GuiProgressBarProperty; + +// ScrollBar +typedef enum { + ARROWS_SIZE = 16, // ScrollBar arrows size + ARROWS_VISIBLE, // ScrollBar arrows visible + SCROLL_SLIDER_PADDING, // ScrollBar slider internal padding + SCROLL_SLIDER_SIZE, // ScrollBar slider size + SCROLL_PADDING, // ScrollBar scroll padding from arrows + SCROLL_SPEED, // ScrollBar scrolling speed +} GuiScrollBarProperty; + +// CheckBox +typedef enum { + CHECK_PADDING = 16 // CheckBox internal check padding +} GuiCheckBoxProperty; + +// ComboBox +typedef enum { + COMBO_BUTTON_WIDTH = 16, // ComboBox right button width + COMBO_BUTTON_SPACING // ComboBox button separation +} GuiComboBoxProperty; + +// DropdownBox +typedef enum { + ARROW_PADDING = 16, // DropdownBox arrow separation from border and items + DROPDOWN_ITEMS_SPACING, // DropdownBox items separation + DROPDOWN_ARROW_HIDDEN, // DropdownBox arrow hidden + DROPDOWN_ROLL_UP // DropdownBox roll up flag: 0-Roll down, 1-Roll up +} GuiDropdownBoxProperty; + +// TextBox/TextBoxMulti/ValueBox/Spinner +typedef enum { + TEXT_READONLY = 16, // TextBox in read-only mode: 0-Text editable, 1-Text read-only +} GuiTextBoxProperty; + +// ValueBox/Spinner +typedef enum { + SPINNER_BUTTON_WIDTH = 16, // Spinner left/right buttons width + SPINNER_BUTTON_SPACING, // Spinner buttons separation +} GuiValueBoxProperty; + +// TabBar +typedef enum { + TAB_ITEMS_WIDTH = 16, // TabBar tab items width + TAB_CLOSE_BUTTON, // TabBar tab close button: 0-Not shown, 1-Shown + TAB_LINE_SIDE, // TabBar tabs side: 0-Bottom, 1-Top +} GuiTabBarProperty; + +// ListView +#define SCROLLBAR_LEFT_SIDE 0 +#define SCROLLBAR_RIGHT_SIDE 1 + +typedef enum { + LIST_ITEMS_HEIGHT = 16, // ListView items height + LIST_ITEMS_SPACING, // ListView items separation + SCROLLBAR_WIDTH, // ListView scrollbar size (usually width) + SCROLLBAR_SIDE, // ListView scrollbar side: 0-Left side, 1-Right Side + LIST_ITEMS_BORDER_NORMAL, // ListView items border enabled in normal state + LIST_ITEMS_BORDER_WIDTH // ListView items border width +} GuiListViewProperty; + +// ColorPicker +typedef enum { + COLOR_SELECTOR_SIZE = 16, // ColorPicker selector square size + HUEBAR_WIDTH, // ColorPicker right hue bar width + HUEBAR_PADDING, // ColorPicker right hue bar separation from panel + HUEBAR_SELECTOR_HEIGHT, // ColorPicker right hue bar selector height + HUEBAR_SELECTOR_OVERFLOW // ColorPicker right hue bar selector overflow +} GuiColorPickerProperty; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +// ... + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- + +#if defined(__cplusplus) +extern "C" { // Prevents name mangling of functions +#endif + +// Global gui state control functions +RAYGUIAPI void GuiEnable(void); // Enable gui controls (global state) +RAYGUIAPI void GuiDisable(void); // Disable gui controls (global state) +RAYGUIAPI void GuiLock(void); // Lock gui controls (global state) +RAYGUIAPI void GuiUnlock(void); // Unlock gui controls (global state) +RAYGUIAPI bool GuiIsLocked(void); // Check if gui is locked (global state) +RAYGUIAPI void GuiSetAlpha(float alpha); // Set gui controls alpha (global state), alpha goes from 0.0f to 1.0f +RAYGUIAPI void GuiSetState(int state); // Set gui state (global state) +RAYGUIAPI int GuiGetState(void); // Get gui state (global state) + +// Font set/get functions +RAYGUIAPI void GuiSetFont(Font font); // Set gui custom font (global state) +RAYGUIAPI Font GuiGetFont(void); // Get gui custom font (global state) + +// Style set/get functions +RAYGUIAPI void GuiSetStyle(int control, int property, int value); // Set one style property +RAYGUIAPI int GuiGetStyle(int control, int property); // Get one style property + +// Styles loading functions +RAYGUIAPI void GuiLoadStyle(const char *fileName); // Load style file over global style variable (.rgs) +RAYGUIAPI void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only) +RAYGUIAPI void GuiLoadStyleDefault(void); // Load style default over global style + +// Tooltips management functions +RAYGUIAPI void GuiEnableTooltip(void); // Enable gui tooltips (global state) +RAYGUIAPI void GuiDisableTooltip(void); // Disable gui tooltips (global state) +RAYGUIAPI void GuiSetTooltip(const char *tooltip); // Set tooltip string + +// Icons functionality +RAYGUIAPI const char *GuiIconText(int iconId, const char *text); // Get text with icon id prepended (if supported) +#if !defined(RAYGUI_NO_ICONS) +RAYGUIAPI void GuiSetIconScale(int scale); // Set default icon drawing size +RAYGUIAPI unsigned int *GuiGetIcons(void); // Get raygui icons data pointer +RAYGUIAPI char **GuiLoadIcons(const char *fileName, bool loadIconsName); // Load raygui icons file (.rgi) into internal icons data +RAYGUIAPI char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName); // Load raygui icons file (.rgi) from memory into internal icons data +RAYGUIAPI void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color); // Draw icon using pixel size at specified position +#endif + +// Utility functions +RAYGUIAPI int GuiGetTextWidth(const char *text); // Get text width considering gui style and icon size (if required) + +// Controls +//---------------------------------------------------------------------------------------------------------- +// Container/separator controls, useful for controls organization +RAYGUIAPI int GuiWindowBox(Rectangle bounds, const char *title); // Window Box control, shows a window that can be closed +RAYGUIAPI int GuiGroupBox(Rectangle bounds, const char *text); // Group Box control with text name +RAYGUIAPI int GuiLine(Rectangle bounds, const char *text); // Line separator control, could contain text +RAYGUIAPI int GuiPanel(Rectangle bounds, const char *text); // Panel control, useful to group controls +RAYGUIAPI int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view); // Scroll Panel control + +// Basic controls set +RAYGUIAPI int GuiLabel(Rectangle bounds, const char *text); // Label control +RAYGUIAPI int GuiButton(Rectangle bounds, const char *text); // Button control, returns true when clicked +RAYGUIAPI int GuiLabelButton(Rectangle bounds, const char *text); // Label button control, returns true when clicked +RAYGUIAPI int GuiToggle(Rectangle bounds, const char *text, bool *active); // Toggle Button control +RAYGUIAPI int GuiToggleGroup(Rectangle bounds, const char *text, int *active); // Toggle Group control +RAYGUIAPI int GuiToggleSlider(Rectangle bounds, const char *text, int *active); // Toggle Slider control +RAYGUIAPI int GuiCheckBox(Rectangle bounds, const char *text, bool *checked); // Check Box control, returns true when active +RAYGUIAPI int GuiComboBox(Rectangle bounds, const char *text, int *active); // Combo Box control + +RAYGUIAPI int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode); // Dropdown Box control +RAYGUIAPI int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Spinner control +RAYGUIAPI int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Value Box control, updates input text with numbers +RAYGUIAPI int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode); // Value box control for float values +RAYGUIAPI int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode); // Text Box control, updates input text + +RAYGUIAPI int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider control +RAYGUIAPI int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider Bar control +RAYGUIAPI int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Progress Bar control +RAYGUIAPI int GuiStatusBar(Rectangle bounds, const char *text); // Status Bar control, shows info text +RAYGUIAPI int GuiDummyRec(Rectangle bounds, const char *text); // Dummy control for placeholders +RAYGUIAPI int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vector2 *mouseCell); // Grid control + +// Advance controls set +RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active); // List View control +RAYGUIAPI int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus); // List View control, using text entries list and returning focus entry +RAYGUIAPI int GuiTabBar(Rectangle bounds, const char *text, int *hscroll, int *active); // Tab Bar control +RAYGUIAPI int GuiTabBarEx(Rectangle bounds, char **text, int count, int *hscroll, int *active, int *focus); // Tab Bar control, using text entries list and returning focus entry +RAYGUIAPI int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *btnText, int *btnActive); // Message Box control, displays a message +RAYGUIAPI int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, char *text, int textSize, const char *btnText, int *btnActive, bool *secretViewActive); // Text Input Box control, ask for text, supports secret +RAYGUIAPI int GuiColorPicker(Rectangle bounds, const char *text, Color *color); // Color Picker control, includes Color bar controls +RAYGUIAPI int GuiColorPanel(Rectangle bounds, const char *text, Color *color); // Color Panel control +RAYGUIAPI int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha); // Color Bar Alpha control +RAYGUIAPI int GuiColorBarHue(Rectangle bounds, const char *text, float *value); // Color Bar Hue control +RAYGUIAPI int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Picker control, using Hue-Saturation-Value color data, includes Color bar controls +RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control, using Hue-Saturation-Value color data +//---------------------------------------------------------------------------------------------------------- + +#if !defined(RAYGUI_NO_ICONS) + +#if !defined(RAYGUI_CUSTOM_ICONS) +//---------------------------------------------------------------------------------- +// Icons enumeration +//---------------------------------------------------------------------------------- +typedef enum { + ICON_NONE = 0, + ICON_FOLDER_FILE_OPEN = 1, + ICON_FILE_SAVE_CLASSIC = 2, + ICON_FOLDER_OPEN = 3, + ICON_FOLDER_SAVE = 4, + ICON_FILE_OPEN = 5, + ICON_FILE_SAVE = 6, + ICON_FILE_EXPORT = 7, + ICON_FILE_ADD = 8, + ICON_FILE_DELETE = 9, + ICON_FILETYPE_TEXT = 10, + ICON_FILETYPE_AUDIO = 11, + ICON_FILETYPE_IMAGE = 12, + ICON_FILETYPE_PLAY = 13, + ICON_FILETYPE_VIDEO = 14, + ICON_FILETYPE_INFO = 15, + ICON_FILE_COPY = 16, + ICON_FILE_CUT = 17, + ICON_FILE_PASTE = 18, + ICON_CURSOR_HAND = 19, + ICON_CURSOR_POINTER = 20, + ICON_CURSOR_CLASSIC = 21, + ICON_PENCIL = 22, + ICON_PENCIL_BIG = 23, + ICON_BRUSH_CLASSIC = 24, + ICON_BRUSH_PAINTER = 25, + ICON_WATER_DROP = 26, + ICON_COLOR_PICKER = 27, + ICON_RUBBER = 28, + ICON_COLOR_BUCKET = 29, + ICON_TEXT_T = 30, + ICON_TEXT_A = 31, + ICON_SCALE = 32, + ICON_RESIZE = 33, + ICON_FILTER_POINT = 34, + ICON_FILTER_BILINEAR = 35, + ICON_CROP = 36, + ICON_CROP_ALPHA = 37, + ICON_SQUARE_TOGGLE = 38, + ICON_SYMMETRY = 39, + ICON_SYMMETRY_HORIZONTAL = 40, + ICON_SYMMETRY_VERTICAL = 41, + ICON_LENS = 42, + ICON_LENS_BIG = 43, + ICON_EYE_ON = 44, + ICON_EYE_OFF = 45, + ICON_FILTER_TOP = 46, + ICON_FILTER = 47, + ICON_TARGET_POINT = 48, + ICON_TARGET_SMALL = 49, + ICON_TARGET_BIG = 50, + ICON_TARGET_MOVE = 51, + ICON_CURSOR_MOVE = 52, + ICON_CURSOR_SCALE = 53, + ICON_CURSOR_SCALE_RIGHT = 54, + ICON_CURSOR_SCALE_LEFT = 55, + ICON_UNDO = 56, + ICON_REDO = 57, + ICON_REREDO = 58, + ICON_MUTATE = 59, + ICON_ROTATE = 60, + ICON_REPEAT = 61, + ICON_SHUFFLE = 62, + ICON_EMPTYBOX = 63, + ICON_TARGET = 64, + ICON_TARGET_SMALL_FILL = 65, + ICON_TARGET_BIG_FILL = 66, + ICON_TARGET_MOVE_FILL = 67, + ICON_CURSOR_MOVE_FILL = 68, + ICON_CURSOR_SCALE_FILL = 69, + ICON_CURSOR_SCALE_RIGHT_FILL = 70, + ICON_CURSOR_SCALE_LEFT_FILL = 71, + ICON_UNDO_FILL = 72, + ICON_REDO_FILL = 73, + ICON_REREDO_FILL = 74, + ICON_MUTATE_FILL = 75, + ICON_ROTATE_FILL = 76, + ICON_REPEAT_FILL = 77, + ICON_SHUFFLE_FILL = 78, + ICON_EMPTYBOX_SMALL = 79, + ICON_BOX = 80, + ICON_BOX_TOP = 81, + ICON_BOX_TOP_RIGHT = 82, + ICON_BOX_RIGHT = 83, + ICON_BOX_BOTTOM_RIGHT = 84, + ICON_BOX_BOTTOM = 85, + ICON_BOX_BOTTOM_LEFT = 86, + ICON_BOX_LEFT = 87, + ICON_BOX_TOP_LEFT = 88, + ICON_BOX_CENTER = 89, + ICON_BOX_CIRCLE_MASK = 90, + ICON_POT = 91, + ICON_ALPHA_MULTIPLY = 92, + ICON_ALPHA_CLEAR = 93, + ICON_DITHERING = 94, + ICON_MIPMAPS = 95, + ICON_BOX_GRID = 96, + ICON_GRID = 97, + ICON_BOX_CORNERS_SMALL = 98, + ICON_BOX_CORNERS_BIG = 99, + ICON_FOUR_BOXES = 100, + ICON_GRID_FILL = 101, + ICON_BOX_MULTISIZE = 102, + ICON_ZOOM_SMALL = 103, + ICON_ZOOM_MEDIUM = 104, + ICON_ZOOM_BIG = 105, + ICON_ZOOM_ALL = 106, + ICON_ZOOM_CENTER = 107, + ICON_BOX_DOTS_SMALL = 108, + ICON_BOX_DOTS_BIG = 109, + ICON_BOX_CONCENTRIC = 110, + ICON_BOX_GRID_BIG = 111, + ICON_OK_TICK = 112, + ICON_CROSS = 113, + ICON_ARROW_LEFT = 114, + ICON_ARROW_RIGHT = 115, + ICON_ARROW_DOWN = 116, + ICON_ARROW_UP = 117, + ICON_ARROW_LEFT_FILL = 118, + ICON_ARROW_RIGHT_FILL = 119, + ICON_ARROW_DOWN_FILL = 120, + ICON_ARROW_UP_FILL = 121, + ICON_AUDIO = 122, + ICON_FX = 123, + ICON_WAVE = 124, + ICON_WAVE_SINUS = 125, + ICON_WAVE_SQUARE = 126, + ICON_WAVE_TRIANGULAR = 127, + ICON_CROSS_SMALL = 128, + ICON_PLAYER_PREVIOUS = 129, + ICON_PLAYER_PLAY_BACK = 130, + ICON_PLAYER_PLAY = 131, + ICON_PLAYER_PAUSE = 132, + ICON_PLAYER_STOP = 133, + ICON_PLAYER_NEXT = 134, + ICON_PLAYER_RECORD = 135, + ICON_MAGNET = 136, + ICON_LOCK_CLOSE = 137, + ICON_LOCK_OPEN = 138, + ICON_CLOCK = 139, + ICON_TOOLS = 140, + ICON_GEAR = 141, + ICON_GEAR_BIG = 142, + ICON_BIN = 143, + ICON_HAND_POINTER = 144, + ICON_LASER = 145, + ICON_COIN = 146, + ICON_EXPLOSION = 147, + ICON_1UP = 148, + ICON_PLAYER = 149, + ICON_PLAYER_JUMP = 150, + ICON_KEY = 151, + ICON_DEMON = 152, + ICON_TEXT_POPUP = 153, + ICON_GEAR_EX = 154, + ICON_CRACK = 155, + ICON_CRACK_POINTS = 156, + ICON_STAR = 157, + ICON_DOOR = 158, + ICON_EXIT = 159, + ICON_MODE_2D = 160, + ICON_MODE_3D = 161, + ICON_CUBE = 162, + ICON_CUBE_FACE_TOP = 163, + ICON_CUBE_FACE_LEFT = 164, + ICON_CUBE_FACE_FRONT = 165, + ICON_CUBE_FACE_BOTTOM = 166, + ICON_CUBE_FACE_RIGHT = 167, + ICON_CUBE_FACE_BACK = 168, + ICON_CAMERA = 169, + ICON_SPECIAL = 170, + ICON_LINK_NET = 171, + ICON_LINK_BOXES = 172, + ICON_LINK_MULTI = 173, + ICON_LINK = 174, + ICON_LINK_BROKE = 175, + ICON_TEXT_NOTES = 176, + ICON_NOTEBOOK = 177, + ICON_SUITCASE = 178, + ICON_SUITCASE_ZIP = 179, + ICON_MAILBOX = 180, + ICON_MONITOR = 181, + ICON_PRINTER = 182, + ICON_PHOTO_CAMERA = 183, + ICON_PHOTO_CAMERA_FLASH = 184, + ICON_HOUSE = 185, + ICON_HEART = 186, + ICON_CORNER = 187, + ICON_VERTICAL_BARS = 188, + ICON_VERTICAL_BARS_FILL = 189, + ICON_LIFE_BARS = 190, + ICON_INFO = 191, + ICON_CROSSLINE = 192, + ICON_HELP = 193, + ICON_FILETYPE_ALPHA = 194, + ICON_FILETYPE_HOME = 195, + ICON_LAYERS_VISIBLE = 196, + ICON_LAYERS = 197, + ICON_WINDOW = 198, + ICON_HIDPI = 199, + ICON_FILETYPE_BINARY = 200, + ICON_HEX = 201, + ICON_SHIELD = 202, + ICON_FILE_NEW = 203, + ICON_FOLDER_ADD = 204, + ICON_ALARM = 205, + ICON_CPU = 206, + ICON_ROM = 207, + ICON_STEP_OVER = 208, + ICON_STEP_INTO = 209, + ICON_STEP_OUT = 210, + ICON_RESTART = 211, + ICON_BREAKPOINT_ON = 212, + ICON_BREAKPOINT_OFF = 213, + ICON_BURGER_MENU = 214, + ICON_CASE_SENSITIVE = 215, + ICON_REG_EXP = 216, + ICON_FOLDER = 217, + ICON_FILE = 218, + ICON_SAND_TIMER = 219, + ICON_WARNING = 220, + ICON_HELP_BOX = 221, + ICON_INFO_BOX = 222, + ICON_PRIORITY = 223, + ICON_LAYERS_ISO = 224, + ICON_LAYERS2 = 225, + ICON_MLAYERS = 226, + ICON_MAPS = 227, + ICON_HOT = 228, + ICON_LABEL = 229, + ICON_NAME_ID = 230, + ICON_SLICING = 231, + ICON_MANUAL_CONTROL = 232, + ICON_COLLISION = 233, + ICON_CIRCLE_ADD = 234, + ICON_CIRCLE_ADD_FILL = 235, + ICON_CIRCLE_WARNING = 236, + ICON_CIRCLE_WARNING_FILL = 237, + ICON_BOX_MORE = 238, + ICON_BOX_MORE_FILL = 239, + ICON_BOX_MINUS = 240, + ICON_BOX_MINUS_FILL = 241, + ICON_UNION = 242, + ICON_INTERSECTION = 243, + ICON_DIFFERENCE = 244, + ICON_SPHERE = 245, + ICON_CYLINDER = 246, + ICON_CONE = 247, + ICON_ELLIPSOID = 248, + ICON_CAPSULE = 249, + ICON_FILETYPE_FONT = 250, + ICON_FILETYPE_3D = 251, + ICON_FILETYPE_CODE_XML = 252, + ICON_FILETYPE_CODE_C = 253, + ICON_FILETYPE_CODE_PYTHON = 254, + ICON_FILETYPE_CODE_JS = 255, + ICON_FILETYPE_ICON = 256, +} GuiIconName; +#endif + +#endif // RAYGUI_NO_ICONS + +#if defined(__cplusplus) +} // Prevents name mangling of functions +#endif + +#endif // RAYGUI_H + +/*********************************************************************************** +* +* RAYGUI IMPLEMENTATION +* +************************************************************************************/ + +#if defined(RAYGUI_IMPLEMENTATION) + +#include // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()] +#include // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy() +#include // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()] +#include // Required for: roundf() [GuiColorPicker()] +#include // Required for: isspace() [GuiTextBox()] + +// Allow custom memory allocators +#if defined(RAYGUI_MALLOC) || defined(RAYGUI_CALLOC) || defined(RAYGUI_FREE) + #if !defined(RAYGUI_MALLOC) || !defined(RAYGUI_CALLOC) || !defined(RAYGUI_FREE) + #error "RAYGUI: if RAYGUI_MALLOC, RAYGUI_CALLOC, or RAYGUI_FREE is customized, all three must be customized" + #endif +#else + #include // Required for: malloc(), calloc(), free() [GuiLoadStyle(), GuiLoadIcons()] + + #define RAYGUI_MALLOC(sz) malloc(sz) + #define RAYGUI_CALLOC(n,sz) calloc(n,sz) + #define RAYGUI_FREE(p) free(p) +#endif + +#ifdef __cplusplus + #define RAYGUI_CLITERAL(name) name +#else + #define RAYGUI_CLITERAL(name) (name) +#endif + +// Check if two rectangles are equal, used to validate a slider bounds as an id +#ifndef CHECK_BOUNDS_ID + #define CHECK_BOUNDS_ID(src, dst) (((int)src.x == (int)dst.x) && ((int)src.y == (int)dst.y) && ((int)src.width == (int)dst.width) && ((int)src.height == (int)dst.height)) +#endif + +#if !defined(RAYGUI_NO_ICONS) && !defined(RAYGUI_CUSTOM_ICONS) + +// Embedded icons, no external file provided +#define RAYGUI_ICON_SIZE 16 // Size of icons in pixels (squared) +#define RAYGUI_ICON_MAX_ICONS 512 // Maximum number of icons +#define RAYGUI_ICON_MAX_FONT_BACKED 257 // Maximum number of icons to back in font atlas +#define RAYGUI_ICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id +#define RAYGUI_ICON_FONT_ATLAS_PADDING 1 // Padding between backed icons in font atlas + +// Icons data is defined by bit array (every bit represents one pixel) +// Those arrays are stored as unsigned int data arrays, so, +// every array element defines 32 pixels (bits) of information +// One icon is defined by 8 int, (8 int*32 bit = 256 bit = 16*16 pixels) +// NOTE: Number of elemens depend on RAYGUI_ICON_SIZE (by default 16x16 pixels) +#define RAYGUI_ICON_DATA_ELEMENTS (RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32) + +//---------------------------------------------------------------------------------- +// Icons data for all gui possible icons (allocated on data segment by default) +// +// NOTE 1: Every icon is codified in binary form, using 1 bit per pixel, so, +// every 16x16 icon requires 8 integers (16*16/32) to be stored +// +// NOTE 2: A different icon set could be loaded over this array using GuiLoadIcons(), +// but loaded icons set must be same RAYGUI_ICON_SIZE and no more than RAYGUI_ICON_MAX_ICONS +// +// guiIcons size is by default: 512*(16*16/32) = 16384 bytes = 16 KB +//---------------------------------------------------------------------------------- +static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_NONE + 0x3ff80000, 0x2f082008, 0x2042207e, 0x40027fc2, 0x40024002, 0x40024002, 0x40024002, 0x00007ffe, // ICON_FOLDER_FILE_OPEN + 0x3ffe0000, 0x44226422, 0x400247e2, 0x5ffa4002, 0x57ea500a, 0x500a500a, 0x40025ffa, 0x00007ffe, // ICON_FILE_SAVE_CLASSIC + 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024002, 0x44424282, 0x793e4102, 0x00000100, // ICON_FOLDER_OPEN + 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024102, 0x44424102, 0x793e4282, 0x00000000, // ICON_FOLDER_SAVE + 0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x24442284, 0x21042104, 0x20042104, 0x00003ffc, // ICON_FILE_OPEN + 0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x21042104, 0x22842444, 0x20042104, 0x00003ffc, // ICON_FILE_SAVE + 0x3ff00000, 0x201c2010, 0x00042004, 0x20041004, 0x20844784, 0x00841384, 0x20042784, 0x00003ffc, // ICON_FILE_EXPORT + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x22042204, 0x22042f84, 0x20042204, 0x00003ffc, // ICON_FILE_ADD + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x25042884, 0x25042204, 0x20042884, 0x00003ffc, // ICON_FILE_DELETE + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // ICON_FILETYPE_TEXT + 0x3ff00000, 0x201c2010, 0x27042004, 0x244424c4, 0x26442444, 0x20642664, 0x20042004, 0x00003ffc, // ICON_FILETYPE_AUDIO + 0x3ff00000, 0x201c2010, 0x26042604, 0x20042004, 0x35442884, 0x2414222c, 0x20042004, 0x00003ffc, // ICON_FILETYPE_IMAGE + 0x3ff00000, 0x201c2010, 0x20c42004, 0x22442144, 0x22442444, 0x20c42144, 0x20042004, 0x00003ffc, // ICON_FILETYPE_PLAY + 0x3ff00000, 0x3ffc2ff0, 0x3f3c2ff4, 0x3dbc2eb4, 0x3dbc2bb4, 0x3f3c2eb4, 0x3ffc2ff4, 0x00002ff4, // ICON_FILETYPE_VIDEO + 0x3ff00000, 0x201c2010, 0x21842184, 0x21842004, 0x21842184, 0x21842184, 0x20042184, 0x00003ffc, // ICON_FILETYPE_INFO + 0x0ff00000, 0x381c0810, 0x28042804, 0x28042804, 0x28042804, 0x28042804, 0x20102ffc, 0x00003ff0, // ICON_FILE_COPY + 0x00000000, 0x701c0000, 0x079c1e14, 0x55a000f0, 0x079c00f0, 0x701c1e14, 0x00000000, 0x00000000, // ICON_FILE_CUT + 0x01c00000, 0x13e41bec, 0x3f841004, 0x204420c4, 0x20442044, 0x20442044, 0x207c2044, 0x00003fc0, // ICON_FILE_PASTE + 0x00000000, 0x3aa00fe0, 0x2abc2aa0, 0x2aa42aa4, 0x20042aa4, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_CURSOR_HAND + 0x00000000, 0x003c000c, 0x030800c8, 0x30100c10, 0x10202020, 0x04400840, 0x01800280, 0x00000000, // ICON_CURSOR_POINTER + 0x00000000, 0x00180000, 0x01f00078, 0x03e007f0, 0x07c003e0, 0x04000e40, 0x00000000, 0x00000000, // ICON_CURSOR_CLASSIC + 0x00000000, 0x04000000, 0x11000a00, 0x04400a80, 0x01100220, 0x00580088, 0x00000038, 0x00000000, // ICON_PENCIL + 0x04000000, 0x15000a00, 0x50402880, 0x14102820, 0x05040a08, 0x015c028c, 0x007c00bc, 0x00000000, // ICON_PENCIL_BIG + 0x01c00000, 0x01400140, 0x01400140, 0x0ff80140, 0x0ff80808, 0x0aa80808, 0x0aa80aa8, 0x00000ff8, // ICON_BRUSH_CLASSIC + 0x1ffc0000, 0x5ffc7ffe, 0x40004000, 0x00807f80, 0x01c001c0, 0x01c001c0, 0x01c001c0, 0x00000080, // ICON_BRUSH_PAINTER + 0x00000000, 0x00800000, 0x01c00080, 0x03e001c0, 0x07f003e0, 0x036006f0, 0x000001c0, 0x00000000, // ICON_WATER_DROP + 0x00000000, 0x3e003800, 0x1f803f80, 0x0c201e40, 0x02080c10, 0x00840104, 0x00380044, 0x00000000, // ICON_COLOR_PICKER + 0x00000000, 0x07800300, 0x1fe00fc0, 0x3f883fd0, 0x0e021f04, 0x02040402, 0x00f00108, 0x00000000, // ICON_RUBBER + 0x00c00000, 0x02800140, 0x08200440, 0x20081010, 0x2ffe3004, 0x03f807fc, 0x00e001f0, 0x00000040, // ICON_COLOR_BUCKET + 0x00000000, 0x21843ffc, 0x01800180, 0x01800180, 0x01800180, 0x01800180, 0x03c00180, 0x00000000, // ICON_TEXT_T + 0x00800000, 0x01400180, 0x06200340, 0x0c100620, 0x1ff80c10, 0x380c1808, 0x70067004, 0x0000f80f, // ICON_TEXT_A + 0x78000000, 0x50004000, 0x00004800, 0x03c003c0, 0x03c003c0, 0x00100000, 0x0002000a, 0x0000000e, // ICON_SCALE + 0x75560000, 0x5e004002, 0x54001002, 0x41001202, 0x408200fe, 0x40820082, 0x40820082, 0x00006afe, // ICON_RESIZE + 0x00000000, 0x3f003f00, 0x3f003f00, 0x3f003f00, 0x00400080, 0x001c0020, 0x001c001c, 0x00000000, // ICON_FILTER_POINT + 0x6d800000, 0x00004080, 0x40804080, 0x40800000, 0x00406d80, 0x001c0020, 0x001c001c, 0x00000000, // ICON_FILTER_BILINEAR + 0x40080000, 0x1ffe2008, 0x14081008, 0x11081208, 0x10481088, 0x10081028, 0x10047ff8, 0x00001002, // ICON_CROP + 0x00100000, 0x3ffc0010, 0x2ab03550, 0x22b02550, 0x20b02150, 0x20302050, 0x2000fff0, 0x00002000, // ICON_CROP_ALPHA + 0x40000000, 0x1ff82000, 0x04082808, 0x01082208, 0x00482088, 0x00182028, 0x35542008, 0x00000002, // ICON_SQUARE_TOGGLE + 0x00000000, 0x02800280, 0x06c006c0, 0x0ea00ee0, 0x1e901eb0, 0x3e883e98, 0x7efc7e8c, 0x00000000, // ICON_SYMMETRY + 0x01000000, 0x05600100, 0x1d480d50, 0x7d423d44, 0x3d447d42, 0x0d501d48, 0x01000560, 0x00000100, // ICON_SYMMETRY_HORIZONTAL + 0x01800000, 0x04200240, 0x10080810, 0x00001ff8, 0x00007ffe, 0x0ff01ff8, 0x03c007e0, 0x00000180, // ICON_SYMMETRY_VERTICAL + 0x00000000, 0x010800f0, 0x02040204, 0x02040204, 0x07f00308, 0x1c000e00, 0x30003800, 0x00000000, // ICON_LENS + 0x00000000, 0x061803f0, 0x08240c0c, 0x08040814, 0x0c0c0804, 0x23f01618, 0x18002400, 0x00000000, // ICON_LENS_BIG + 0x00000000, 0x00000000, 0x1c7007c0, 0x638e3398, 0x1c703398, 0x000007c0, 0x00000000, 0x00000000, // ICON_EYE_ON + 0x00000000, 0x10002000, 0x04700fc0, 0x610e3218, 0x1c703098, 0x001007a0, 0x00000008, 0x00000000, // ICON_EYE_OFF + 0x00000000, 0x00007ffc, 0x40047ffc, 0x10102008, 0x04400820, 0x02800280, 0x02800280, 0x00000100, // ICON_FILTER_TOP + 0x00000000, 0x40027ffe, 0x10082004, 0x04200810, 0x02400240, 0x02400240, 0x01400240, 0x000000c0, // ICON_FILTER + 0x00800000, 0x00800080, 0x00000080, 0x3c9e0000, 0x00000000, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_POINT + 0x00800000, 0x00800080, 0x00800080, 0x3f7e01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_SMALL + 0x00800000, 0x00800080, 0x03e00080, 0x3e3e0220, 0x03e00220, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_BIG + 0x01000000, 0x04400280, 0x01000100, 0x43842008, 0x43849ab2, 0x01002008, 0x04400100, 0x01000280, // ICON_TARGET_MOVE + 0x01000000, 0x04400280, 0x01000100, 0x41042108, 0x41049ff2, 0x01002108, 0x04400100, 0x01000280, // ICON_CURSOR_MOVE + 0x781e0000, 0x500a4002, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x4002500a, 0x0000781e, // ICON_CURSOR_SCALE + 0x00000000, 0x20003c00, 0x24002800, 0x01000200, 0x00400080, 0x00140024, 0x003c0004, 0x00000000, // ICON_CURSOR_SCALE_RIGHT + 0x00000000, 0x0004003c, 0x00240014, 0x00800040, 0x02000100, 0x28002400, 0x3c002000, 0x00000000, // ICON_CURSOR_SCALE_LEFT + 0x00000000, 0x00100020, 0x10101fc8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // ICON_UNDO + 0x00000000, 0x08000400, 0x080813f8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // ICON_REDO + 0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3f902020, 0x00400020, 0x00000000, // ICON_REREDO + 0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3fc82010, 0x00200010, 0x00000000, // ICON_MUTATE + 0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18101020, 0x00100fc8, 0x00000020, // ICON_ROTATE + 0x00000000, 0x04000200, 0x240429fc, 0x20042204, 0x20442004, 0x3f942024, 0x00400020, 0x00000000, // ICON_REPEAT + 0x00000000, 0x20001000, 0x22104c0e, 0x00801120, 0x11200040, 0x4c0e2210, 0x10002000, 0x00000000, // ICON_SHUFFLE + 0x7ffe0000, 0x50024002, 0x44024802, 0x41024202, 0x40424082, 0x40124022, 0x4002400a, 0x00007ffe, // ICON_EMPTYBOX + 0x00800000, 0x03e00080, 0x08080490, 0x3c9e0808, 0x08080808, 0x03e00490, 0x00800080, 0x00000000, // ICON_TARGET + 0x00800000, 0x00800080, 0x00800080, 0x3ffe01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_SMALL_FILL + 0x00800000, 0x00800080, 0x03e00080, 0x3ffe03e0, 0x03e003e0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_BIG_FILL + 0x01000000, 0x07c00380, 0x01000100, 0x638c2008, 0x638cfbbe, 0x01002008, 0x07c00100, 0x01000380, // ICON_TARGET_MOVE_FILL + 0x01000000, 0x07c00380, 0x01000100, 0x610c2108, 0x610cfffe, 0x01002108, 0x07c00100, 0x01000380, // ICON_CURSOR_MOVE_FILL + 0x781e0000, 0x6006700e, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x700e6006, 0x0000781e, // ICON_CURSOR_SCALE_FILL + 0x00000000, 0x38003c00, 0x24003000, 0x01000200, 0x00400080, 0x000c0024, 0x003c001c, 0x00000000, // ICON_CURSOR_SCALE_RIGHT_FILL + 0x00000000, 0x001c003c, 0x0024000c, 0x00800040, 0x02000100, 0x30002400, 0x3c003800, 0x00000000, // ICON_CURSOR_SCALE_LEFT_FILL + 0x00000000, 0x00300020, 0x10301ff8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // ICON_UNDO_FILL + 0x00000000, 0x0c000400, 0x0c081ff8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // ICON_REDO_FILL + 0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3ff02060, 0x00400060, 0x00000000, // ICON_REREDO_FILL + 0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3ff82030, 0x00200030, 0x00000000, // ICON_MUTATE_FILL + 0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18301020, 0x00300ff8, 0x00000020, // ICON_ROTATE_FILL + 0x00000000, 0x06000200, 0x26042ffc, 0x20042204, 0x20442004, 0x3ff42064, 0x00400060, 0x00000000, // ICON_REPEAT_FILL + 0x00000000, 0x30001000, 0x32107c0e, 0x00801120, 0x11200040, 0x7c0e3210, 0x10003000, 0x00000000, // ICON_SHUFFLE_FILL + 0x00000000, 0x30043ffc, 0x24042804, 0x21042204, 0x20442084, 0x20142024, 0x3ffc200c, 0x00000000, // ICON_EMPTYBOX_SMALL + 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX + 0x00000000, 0x23c43ffc, 0x23c423c4, 0x200423c4, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP + 0x00000000, 0x3e043ffc, 0x3e043e04, 0x20043e04, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP_RIGHT + 0x00000000, 0x20043ffc, 0x20042004, 0x3e043e04, 0x3e043e04, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_RIGHT + 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x3e042004, 0x3e043e04, 0x3ffc3e04, 0x00000000, // ICON_BOX_BOTTOM_RIGHT + 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x23c42004, 0x23c423c4, 0x3ffc23c4, 0x00000000, // ICON_BOX_BOTTOM + 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x207c2004, 0x207c207c, 0x3ffc207c, 0x00000000, // ICON_BOX_BOTTOM_LEFT + 0x00000000, 0x20043ffc, 0x20042004, 0x207c207c, 0x207c207c, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_LEFT + 0x00000000, 0x207c3ffc, 0x207c207c, 0x2004207c, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP_LEFT + 0x00000000, 0x20043ffc, 0x20042004, 0x23c423c4, 0x23c423c4, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_CENTER + 0x7ffe0000, 0x40024002, 0x47e24182, 0x4ff247e2, 0x47e24ff2, 0x418247e2, 0x40024002, 0x00007ffe, // ICON_BOX_CIRCLE_MASK + 0x7fff0000, 0x40014001, 0x40014001, 0x49555ddd, 0x4945495d, 0x400149c5, 0x40014001, 0x00007fff, // ICON_POT + 0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x404e40ce, 0x48125432, 0x4006540e, 0x00007ffe, // ICON_ALPHA_MULTIPLY + 0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x5c4e40ce, 0x44124432, 0x40065c0e, 0x00007ffe, // ICON_ALPHA_CLEAR + 0x7ffe0000, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x00007ffe, // ICON_DITHERING + 0x07fe0000, 0x1ffa0002, 0x7fea000a, 0x402a402a, 0x5b2a512a, 0x5128552a, 0x40205128, 0x00007fe0, // ICON_MIPMAPS + 0x00000000, 0x1ff80000, 0x12481248, 0x12481ff8, 0x1ff81248, 0x12481248, 0x00001ff8, 0x00000000, // ICON_BOX_GRID + 0x12480000, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x00001248, // ICON_GRID + 0x00000000, 0x1c380000, 0x1c3817e8, 0x08100810, 0x08100810, 0x17e81c38, 0x00001c38, 0x00000000, // ICON_BOX_CORNERS_SMALL + 0x700e0000, 0x700e5ffa, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x5ffa700e, 0x0000700e, // ICON_BOX_CORNERS_BIG + 0x3f7e0000, 0x21422142, 0x21422142, 0x00003f7e, 0x21423f7e, 0x21422142, 0x3f7e2142, 0x00000000, // ICON_FOUR_BOXES + 0x00000000, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x00000000, // ICON_GRID_FILL + 0x7ffe0000, 0x7ffe7ffe, 0x77fe7000, 0x77fe77fe, 0x777e7700, 0x777e777e, 0x777e777e, 0x0000777e, // ICON_BOX_MULTISIZE + 0x781e0000, 0x40024002, 0x00004002, 0x01800000, 0x00000180, 0x40020000, 0x40024002, 0x0000781e, // ICON_ZOOM_SMALL + 0x781e0000, 0x40024002, 0x00004002, 0x03c003c0, 0x03c003c0, 0x40020000, 0x40024002, 0x0000781e, // ICON_ZOOM_MEDIUM + 0x781e0000, 0x40024002, 0x07e04002, 0x07e007e0, 0x07e007e0, 0x400207e0, 0x40024002, 0x0000781e, // ICON_ZOOM_BIG + 0x781e0000, 0x5ffa4002, 0x1ff85ffa, 0x1ff81ff8, 0x1ff81ff8, 0x5ffa1ff8, 0x40025ffa, 0x0000781e, // ICON_ZOOM_ALL + 0x00000000, 0x2004381c, 0x00002004, 0x00000000, 0x00000000, 0x20040000, 0x381c2004, 0x00000000, // ICON_ZOOM_CENTER + 0x00000000, 0x1db80000, 0x10081008, 0x10080000, 0x00001008, 0x10081008, 0x00001db8, 0x00000000, // ICON_BOX_DOTS_SMALL + 0x35560000, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x35562002, 0x00000000, // ICON_BOX_DOTS_BIG + 0x7ffe0000, 0x40024002, 0x48124ff2, 0x49924812, 0x48124992, 0x4ff24812, 0x40024002, 0x00007ffe, // ICON_BOX_CONCENTRIC + 0x00000000, 0x10841ffc, 0x10841084, 0x1ffc1084, 0x10841084, 0x10841084, 0x00001ffc, 0x00000000, // ICON_BOX_GRID_BIG + 0x00000000, 0x00000000, 0x10000000, 0x04000800, 0x01040200, 0x00500088, 0x00000020, 0x00000000, // ICON_OK_TICK + 0x00000000, 0x10080000, 0x04200810, 0x01800240, 0x02400180, 0x08100420, 0x00001008, 0x00000000, // ICON_CROSS + 0x00000000, 0x02000000, 0x00800100, 0x00200040, 0x00200010, 0x00800040, 0x02000100, 0x00000000, // ICON_ARROW_LEFT + 0x00000000, 0x00400000, 0x01000080, 0x04000200, 0x04000800, 0x01000200, 0x00400080, 0x00000000, // ICON_ARROW_RIGHT + 0x00000000, 0x00000000, 0x00000000, 0x08081004, 0x02200410, 0x00800140, 0x00000000, 0x00000000, // ICON_ARROW_DOWN + 0x00000000, 0x00000000, 0x01400080, 0x04100220, 0x10040808, 0x00000000, 0x00000000, 0x00000000, // ICON_ARROW_UP + 0x00000000, 0x02000000, 0x03800300, 0x03e003c0, 0x03e003f0, 0x038003c0, 0x02000300, 0x00000000, // ICON_ARROW_LEFT_FILL + 0x00000000, 0x00400000, 0x01c000c0, 0x07c003c0, 0x07c00fc0, 0x01c003c0, 0x004000c0, 0x00000000, // ICON_ARROW_RIGHT_FILL + 0x00000000, 0x00000000, 0x00000000, 0x0ff81ffc, 0x03e007f0, 0x008001c0, 0x00000000, 0x00000000, // ICON_ARROW_DOWN_FILL + 0x00000000, 0x00000000, 0x01c00080, 0x07f003e0, 0x1ffc0ff8, 0x00000000, 0x00000000, 0x00000000, // ICON_ARROW_UP_FILL + 0x00000000, 0x18a008c0, 0x32881290, 0x24822686, 0x26862482, 0x12903288, 0x08c018a0, 0x00000000, // ICON_AUDIO + 0x00000000, 0x04800780, 0x004000c0, 0x662000f0, 0x08103c30, 0x130a0e18, 0x0000318e, 0x00000000, // ICON_FX + 0x00000000, 0x00800000, 0x08880888, 0x2aaa0a8a, 0x0a8a2aaa, 0x08880888, 0x00000080, 0x00000000, // ICON_WAVE + 0x00000000, 0x00600000, 0x01080090, 0x02040108, 0x42044204, 0x24022402, 0x00001800, 0x00000000, // ICON_WAVE_SINUS + 0x00000000, 0x07f80000, 0x04080408, 0x04080408, 0x04080408, 0x7c0e0408, 0x00000000, 0x00000000, // ICON_WAVE_SQUARE + 0x00000000, 0x00000000, 0x00a00040, 0x22084110, 0x08021404, 0x00000000, 0x00000000, 0x00000000, // ICON_WAVE_TRIANGULAR + 0x00000000, 0x00000000, 0x04200000, 0x01800240, 0x02400180, 0x00000420, 0x00000000, 0x00000000, // ICON_CROSS_SMALL + 0x00000000, 0x18380000, 0x12281428, 0x10a81128, 0x112810a8, 0x14281228, 0x00001838, 0x00000000, // ICON_PLAYER_PREVIOUS + 0x00000000, 0x18000000, 0x11801600, 0x10181060, 0x10601018, 0x16001180, 0x00001800, 0x00000000, // ICON_PLAYER_PLAY_BACK + 0x00000000, 0x00180000, 0x01880068, 0x18080608, 0x06081808, 0x00680188, 0x00000018, 0x00000000, // ICON_PLAYER_PLAY + 0x00000000, 0x1e780000, 0x12481248, 0x12481248, 0x12481248, 0x12481248, 0x00001e78, 0x00000000, // ICON_PLAYER_PAUSE + 0x00000000, 0x1ff80000, 0x10081008, 0x10081008, 0x10081008, 0x10081008, 0x00001ff8, 0x00000000, // ICON_PLAYER_STOP + 0x00000000, 0x1c180000, 0x14481428, 0x15081488, 0x14881508, 0x14281448, 0x00001c18, 0x00000000, // ICON_PLAYER_NEXT + 0x00000000, 0x03c00000, 0x08100420, 0x10081008, 0x10081008, 0x04200810, 0x000003c0, 0x00000000, // ICON_PLAYER_RECORD + 0x00000000, 0x0c3007e0, 0x13c81818, 0x14281668, 0x14281428, 0x1c381c38, 0x08102244, 0x00000000, // ICON_MAGNET + 0x07c00000, 0x08200820, 0x3ff80820, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // ICON_LOCK_CLOSE + 0x07c00000, 0x08000800, 0x3ff80800, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // ICON_LOCK_OPEN + 0x01c00000, 0x0c180770, 0x3086188c, 0x60832082, 0x60034781, 0x30062002, 0x0c18180c, 0x01c00770, // ICON_CLOCK + 0x0a200000, 0x1b201b20, 0x04200e20, 0x04200420, 0x04700420, 0x0e700e70, 0x0e700e70, 0x04200e70, // ICON_TOOLS + 0x01800000, 0x3bdc318c, 0x0ff01ff8, 0x7c3e1e78, 0x1e787c3e, 0x1ff80ff0, 0x318c3bdc, 0x00000180, // ICON_GEAR + 0x01800000, 0x3ffc318c, 0x1c381ff8, 0x781e1818, 0x1818781e, 0x1ff81c38, 0x318c3ffc, 0x00000180, // ICON_GEAR_BIG + 0x00000000, 0x08080ff8, 0x08081ffc, 0x0aa80aa8, 0x0aa80aa8, 0x0aa80aa8, 0x08080aa8, 0x00000ff8, // ICON_BIN + 0x00000000, 0x00000000, 0x20043ffc, 0x08043f84, 0x04040f84, 0x04040784, 0x000007fc, 0x00000000, // ICON_HAND_POINTER + 0x00000000, 0x24400400, 0x00001480, 0x6efe0e00, 0x00000e00, 0x24401480, 0x00000400, 0x00000000, // ICON_LASER + 0x00000000, 0x03c00000, 0x08300460, 0x11181118, 0x11181118, 0x04600830, 0x000003c0, 0x00000000, // ICON_COIN + 0x00000000, 0x10880080, 0x06c00810, 0x366c07e0, 0x07e00240, 0x00001768, 0x04200240, 0x00000000, // ICON_EXPLOSION + 0x00000000, 0x3d280000, 0x2528252c, 0x3d282528, 0x05280528, 0x05e80528, 0x00000000, 0x00000000, // ICON_1UP + 0x01800000, 0x03c003c0, 0x018003c0, 0x0ff007e0, 0x0bd00bd0, 0x0a500bd0, 0x02400240, 0x02400240, // ICON_PLAYER + 0x01800000, 0x03c003c0, 0x118013c0, 0x03c81ff8, 0x07c003c8, 0x04400440, 0x0c080478, 0x00000000, // ICON_PLAYER_JUMP + 0x3ff80000, 0x30183ff8, 0x30183018, 0x3ff83ff8, 0x03000300, 0x03c003c0, 0x03e00300, 0x000003e0, // ICON_KEY + 0x3ff80000, 0x3ff83ff8, 0x33983ff8, 0x3ff83398, 0x3ff83ff8, 0x00000540, 0x0fe00aa0, 0x00000fe0, // ICON_DEMON + 0x00000000, 0x0ff00000, 0x20041008, 0x25442004, 0x10082004, 0x06000bf0, 0x00000300, 0x00000000, // ICON_TEXT_POPUP + 0x00000000, 0x11440000, 0x07f00be8, 0x1c1c0e38, 0x1c1c0c18, 0x07f00e38, 0x11440be8, 0x00000000, // ICON_GEAR_EX + 0x00000000, 0x20080000, 0x0c601010, 0x07c00fe0, 0x07c007c0, 0x0c600fe0, 0x20081010, 0x00000000, // ICON_CRACK + 0x00000000, 0x20080000, 0x0c601010, 0x04400fe0, 0x04405554, 0x0c600fe0, 0x20081010, 0x00000000, // ICON_CRACK_POINTS + 0x00000000, 0x00800080, 0x01c001c0, 0x1ffc3ffe, 0x03e007f0, 0x07f003e0, 0x0c180770, 0x00000808, // ICON_STAR + 0x0ff00000, 0x08180810, 0x08100818, 0x0a100810, 0x08180810, 0x08100818, 0x08100810, 0x00001ff8, // ICON_DOOR + 0x0ff00000, 0x08100810, 0x08100810, 0x10100010, 0x4f902010, 0x10102010, 0x08100010, 0x00000ff0, // ICON_EXIT + 0x00040000, 0x001f000e, 0x0ef40004, 0x12f41284, 0x0ef41214, 0x10040004, 0x7ffc3004, 0x10003000, // ICON_MODE_2D + 0x78040000, 0x501f600e, 0x0ef44004, 0x12f41284, 0x0ef41284, 0x10140004, 0x7ffc300c, 0x10003000, // ICON_MODE_3D + 0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // ICON_CUBE + 0x7fe00000, 0x5ff87ff0, 0x47fe4ffc, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // ICON_CUBE_FACE_TOP + 0x7fe00000, 0x50386030, 0x47c2483c, 0x443e443e, 0x443e443e, 0x241e75fe, 0x0c06140e, 0x000007fe, // ICON_CUBE_FACE_LEFT + 0x7fe00000, 0x50286030, 0x47fe4804, 0x47fe47fe, 0x47fe47fe, 0x27fe77fe, 0x0ffe17fe, 0x000007fe, // ICON_CUBE_FACE_FRONT + 0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x3bf27be2, 0x0bfe1bfa, 0x000007fe, // ICON_CUBE_FACE_BOTTOM + 0x7fe00000, 0x70286030, 0x7ffe7804, 0x7c227c02, 0x7c227c22, 0x3c127de2, 0x0c061c0a, 0x000007fe, // ICON_CUBE_FACE_RIGHT + 0x7fe00000, 0x6fe85ff0, 0x781e77e4, 0x7be27be2, 0x7be27be2, 0x24127be2, 0x0c06140a, 0x000007fe, // ICON_CUBE_FACE_BACK + 0x00000000, 0x2a0233fe, 0x22022602, 0x22022202, 0x2a022602, 0x00a033fe, 0x02080110, 0x00000000, // ICON_CAMERA + 0x00000000, 0x200c3ffc, 0x000c000c, 0x3ffc000c, 0x30003000, 0x30003000, 0x3ffc3004, 0x00000000, // ICON_SPECIAL + 0x00000000, 0x0022003e, 0x012201e2, 0x0100013e, 0x01000100, 0x79000100, 0x4f004900, 0x00007800, // ICON_LINK_NET + 0x00000000, 0x44007c00, 0x45004600, 0x00627cbe, 0x00620022, 0x45007cbe, 0x44004600, 0x00007c00, // ICON_LINK_BOXES + 0x00000000, 0x0044007c, 0x0010007c, 0x3f100010, 0x3f1021f0, 0x3f100010, 0x3f0021f0, 0x00000000, // ICON_LINK_MULTI + 0x00000000, 0x0044007c, 0x00440044, 0x0010007c, 0x00100010, 0x44107c10, 0x440047f0, 0x00007c00, // ICON_LINK + 0x00000000, 0x0044007c, 0x00440044, 0x0000007c, 0x00000010, 0x44007c10, 0x44004550, 0x00007c00, // ICON_LINK_BROKE + 0x02a00000, 0x22a43ffc, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // ICON_TEXT_NOTES + 0x3ffc0000, 0x20042004, 0x245e27c4, 0x27c42444, 0x2004201e, 0x201e2004, 0x20042004, 0x00003ffc, // ICON_NOTEBOOK + 0x00000000, 0x07e00000, 0x04200420, 0x24243ffc, 0x24242424, 0x24242424, 0x3ffc2424, 0x00000000, // ICON_SUITCASE + 0x00000000, 0x0fe00000, 0x08200820, 0x40047ffc, 0x7ffc5554, 0x40045554, 0x7ffc4004, 0x00000000, // ICON_SUITCASE_ZIP + 0x00000000, 0x20043ffc, 0x3ffc2004, 0x13c81008, 0x100813c8, 0x10081008, 0x1ff81008, 0x00000000, // ICON_MAILBOX + 0x00000000, 0x40027ffe, 0x5ffa5ffa, 0x5ffa5ffa, 0x40025ffa, 0x03c07ffe, 0x1ff81ff8, 0x00000000, // ICON_MONITOR + 0x0ff00000, 0x6bfe7ffe, 0x7ffe7ffe, 0x68167ffe, 0x08106816, 0x08100810, 0x0ff00810, 0x00000000, // ICON_PRINTER + 0x3ff80000, 0xfffe2008, 0x870a8002, 0x904a888a, 0x904a904a, 0x870a888a, 0xfffe8002, 0x00000000, // ICON_PHOTO_CAMERA + 0x0fc00000, 0xfcfe0cd8, 0x8002fffe, 0x84428382, 0x84428442, 0x80028382, 0xfffe8002, 0x00000000, // ICON_PHOTO_CAMERA_FLASH + 0x00000000, 0x02400180, 0x08100420, 0x20041008, 0x23c42004, 0x22442244, 0x3ffc2244, 0x00000000, // ICON_HOUSE + 0x00000000, 0x1c700000, 0x3ff83ef8, 0x3ff83ff8, 0x0fe01ff0, 0x038007c0, 0x00000100, 0x00000000, // ICON_HEART + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xe000c000, // ICON_CORNER + 0x00000000, 0x14001c00, 0x15c01400, 0x15401540, 0x155c1540, 0x15541554, 0x1ddc1554, 0x00000000, // ICON_VERTICAL_BARS + 0x00000000, 0x03000300, 0x1b001b00, 0x1b601b60, 0x1b6c1b60, 0x1b6c1b6c, 0x1b6c1b6c, 0x00000000, // ICON_VERTICAL_BARS_FILL + 0x00000000, 0x00000000, 0x403e7ffe, 0x7ffe403e, 0x7ffe0000, 0x43fe43fe, 0x00007ffe, 0x00000000, // ICON_LIFE_BARS + 0x7ffc0000, 0x43844004, 0x43844284, 0x43844004, 0x42844284, 0x42844284, 0x40044384, 0x00007ffc, // ICON_INFO + 0x40008000, 0x10002000, 0x04000800, 0x01000200, 0x00400080, 0x00100020, 0x00040008, 0x00010002, // ICON_CROSSLINE + 0x00000000, 0x1ff01ff0, 0x18301830, 0x1f001830, 0x03001f00, 0x00000300, 0x03000300, 0x00000000, // ICON_HELP + 0x3ff00000, 0x2abc3550, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x00003ffc, // ICON_FILETYPE_ALPHA + 0x3ff00000, 0x201c2010, 0x22442184, 0x28142424, 0x29942814, 0x2ff42994, 0x20042004, 0x00003ffc, // ICON_FILETYPE_HOME + 0x07fe0000, 0x04020402, 0x7fe20402, 0x44224422, 0x44224422, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_LAYERS_VISIBLE + 0x07fe0000, 0x04020402, 0x7c020402, 0x44024402, 0x44024402, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_LAYERS + 0x00000000, 0x40027ffe, 0x7ffe4002, 0x40024002, 0x40024002, 0x40024002, 0x7ffe4002, 0x00000000, // ICON_WINDOW + 0x09100000, 0x09f00910, 0x09100910, 0x00000910, 0x24a2779e, 0x27a224a2, 0x709e20a2, 0x00000000, // ICON_HIDPI + 0x3ff00000, 0x201c2010, 0x2a842e84, 0x2e842a84, 0x2ba42004, 0x2aa42aa4, 0x20042ba4, 0x00003ffc, // ICON_FILETYPE_BINARY + 0x00000000, 0x00000000, 0x00120012, 0x4a5e4bd2, 0x485233d2, 0x00004bd2, 0x00000000, 0x00000000, // ICON_HEX + 0x01800000, 0x381c0660, 0x23c42004, 0x23c42044, 0x13c82204, 0x08101008, 0x02400420, 0x00000180, // ICON_SHIELD + 0x007e0000, 0x20023fc2, 0x40227fe2, 0x400a403a, 0x400a400a, 0x400a400a, 0x4008400e, 0x00007ff8, // ICON_FILE_NEW + 0x00000000, 0x0042007e, 0x40027fc2, 0x44024002, 0x5f024402, 0x44024402, 0x7ffe4002, 0x00000000, // ICON_FOLDER_ADD + 0x44220000, 0x12482244, 0xf3cf0000, 0x14280420, 0x48122424, 0x08100810, 0x1ff81008, 0x03c00420, // ICON_ALARM + 0x0aa00000, 0x1ff80aa0, 0x1068700e, 0x1008706e, 0x1008700e, 0x1008700e, 0x0aa01ff8, 0x00000aa0, // ICON_CPU + 0x07e00000, 0x04201db8, 0x04a01c38, 0x04a01d38, 0x04a01d38, 0x04a01d38, 0x04201d38, 0x000007e0, // ICON_ROM + 0x00000000, 0x03c00000, 0x3c382ff0, 0x3c04380c, 0x01800000, 0x03c003c0, 0x00000180, 0x00000000, // ICON_STEP_OVER + 0x01800000, 0x01800180, 0x01800180, 0x03c007e0, 0x00000180, 0x01800000, 0x03c003c0, 0x00000180, // ICON_STEP_INTO + 0x01800000, 0x07e003c0, 0x01800180, 0x01800180, 0x00000180, 0x01800000, 0x03c003c0, 0x00000180, // ICON_STEP_OUT + 0x00000000, 0x0ff003c0, 0x181c1c34, 0x303c301c, 0x30003000, 0x1c301800, 0x03c00ff0, 0x00000000, // ICON_RESTART + 0x00000000, 0x00000000, 0x07e003c0, 0x0ff00ff0, 0x0ff00ff0, 0x03c007e0, 0x00000000, 0x00000000, // ICON_BREAKPOINT_ON + 0x00000000, 0x00000000, 0x042003c0, 0x08100810, 0x08100810, 0x03c00420, 0x00000000, 0x00000000, // ICON_BREAKPOINT_OFF + 0x00000000, 0x00000000, 0x1ff81ff8, 0x1ff80000, 0x00001ff8, 0x1ff81ff8, 0x00000000, 0x00000000, // ICON_BURGER_MENU + 0x00000000, 0x00000000, 0x00880070, 0x0c880088, 0x1e8810f8, 0x3e881288, 0x00000000, 0x00000000, // ICON_CASE_SENSITIVE + 0x00000000, 0x02000000, 0x07000a80, 0x07001fc0, 0x02000a80, 0x00300030, 0x00000000, 0x00000000, // ICON_REG_EXP + 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x40024002, 0x40024002, 0x7ffe4002, 0x00000000, // ICON_FOLDER + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x00003ffc, // ICON_FILE + 0x1ff00000, 0x20082008, 0x17d02fe8, 0x05400ba0, 0x09200540, 0x23881010, 0x2fe827c8, 0x00001ff0, // ICON_SAND_TIMER + 0x01800000, 0x02400240, 0x05a00420, 0x09900990, 0x11881188, 0x21842004, 0x40024182, 0x00003ffc, // ICON_WARNING + 0x7ffe0000, 0x4ff24002, 0x4c324ff2, 0x4f824c02, 0x41824f82, 0x41824002, 0x40024182, 0x00007ffe, // ICON_HELP_BOX + 0x7ffe0000, 0x41824002, 0x40024182, 0x41824182, 0x41824182, 0x41824182, 0x40024182, 0x00007ffe, // ICON_INFO_BOX + 0x01800000, 0x04200240, 0x10080810, 0x7bde2004, 0x0a500a50, 0x08500bd0, 0x08100850, 0x00000ff0, // ICON_PRIORITY + 0x01800000, 0x18180660, 0x80016006, 0x98196006, 0x99996666, 0x19986666, 0x01800660, 0x00000000, // ICON_LAYERS_ISO + 0x07fe0000, 0x1c020402, 0x74021402, 0x54025402, 0x54025402, 0x500857fe, 0x40205ff8, 0x00007fe0, // ICON_LAYERS2 + 0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x422a422a, 0x422e422a, 0x40384e28, 0x00007fe0, // ICON_MLAYERS + 0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x5b2a512a, 0x512e552a, 0x40385128, 0x00007fe0, // ICON_MAPS + 0x04200000, 0x1cf00c60, 0x11f019f0, 0x0f3807b8, 0x1e3c0f3c, 0x1c1c1e1c, 0x1e3c1c1c, 0x00000f70, // ICON_HOT + 0x00000000, 0x20803f00, 0x2a202e40, 0x20082e10, 0x08021004, 0x02040402, 0x00900108, 0x00000060, // ICON_LABEL + 0x00000000, 0x042007e0, 0x47e27c3e, 0x4ffa4002, 0x47fa4002, 0x4ffa4002, 0x7ffe4002, 0x00000000, // ICON_NAME_ID + 0x7fe00000, 0x402e4020, 0x43ce5e0a, 0x40504078, 0x438e4078, 0x402e5e0a, 0x7fe04020, 0x00000000, // ICON_SLICING + 0x00000000, 0x40027ffe, 0x47c24002, 0x55425d42, 0x55725542, 0x50125552, 0x10105016, 0x00001ff0, // ICON_MANUAL_CONTROL + 0x7ffe0000, 0x43c24002, 0x48124422, 0x500a500a, 0x500a500a, 0x44224812, 0x400243c2, 0x00007ffe, // ICON_COLLISION + 0x03c00000, 0x10080c30, 0x21842184, 0x4ff24182, 0x41824ff2, 0x21842184, 0x0c301008, 0x000003c0, // ICON_CIRCLE_ADD + 0x03c00000, 0x1ff80ff0, 0x3e7c3e7c, 0x700e7e7e, 0x7e7e700e, 0x3e7c3e7c, 0x0ff01ff8, 0x000003c0, // ICON_CIRCLE_ADD_FILL + 0x03c00000, 0x10080c30, 0x21842184, 0x41824182, 0x40024182, 0x21842184, 0x0c301008, 0x000003c0, // ICON_CIRCLE_WARNING + 0x03c00000, 0x1ff80ff0, 0x3e7c3e7c, 0x7e7e7e7e, 0x7ffe7e7e, 0x3e7c3e7c, 0x0ff01ff8, 0x000003c0, // ICON_CIRCLE_WARNING_FILL + 0x00000000, 0x10041ffc, 0x10841004, 0x13e41084, 0x10841084, 0x10041004, 0x00001ffc, 0x00000000, // ICON_BOX_MORE + 0x00000000, 0x1ffc1ffc, 0x1f7c1ffc, 0x1c1c1f7c, 0x1f7c1f7c, 0x1ffc1ffc, 0x00001ffc, 0x00000000, // ICON_BOX_MORE_FILL + 0x00000000, 0x1ffc1ffc, 0x1ffc1ffc, 0x1c1c1ffc, 0x1ffc1ffc, 0x1ffc1ffc, 0x00001ffc, 0x00000000, // ICON_BOX_MINUS + 0x00000000, 0x10041ffc, 0x10041004, 0x13e41004, 0x10041004, 0x10041004, 0x00001ffc, 0x00000000, // ICON_BOX_MINUS_FILL + 0x07fe0000, 0x055606aa, 0x7ff606aa, 0x55766eba, 0x55766eaa, 0x55606ffe, 0x55606aa0, 0x00007fe0, // ICON_UNION + 0x07fe0000, 0x04020402, 0x7fe20402, 0x456246a2, 0x456246a2, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_INTERSECTION + 0x07fe0000, 0x055606aa, 0x7ff606aa, 0x4436442a, 0x4436442a, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_DIFFERENCE + 0x03c00000, 0x10080c30, 0x20042004, 0x60064002, 0x47e2581a, 0x20042004, 0x0c301008, 0x000003c0, // ICON_SPHERE + 0x03e00000, 0x08080410, 0x0c180808, 0x08080be8, 0x08080808, 0x08080808, 0x04100808, 0x000003e0, // ICON_CYLINDER + 0x00800000, 0x01400140, 0x02200220, 0x04100410, 0x08080808, 0x1c1c13e4, 0x08081004, 0x000007f0, // ICON_CONE + 0x00000000, 0x07e00000, 0x20841918, 0x40824082, 0x40824082, 0x19182084, 0x000007e0, 0x00000000, // ICON_ELLIPSOID + 0x00000000, 0x00000000, 0x20041ff8, 0x40024002, 0x40024002, 0x1ff82004, 0x00000000, 0x00000000, // ICON_CAPSULE + 0x3ff00000, 0x201c2010, 0x21042004, 0x22842384, 0x264426c4, 0x2c242fe4, 0x20043e74, 0x00003ffc, // ICON_FILETYPE_FONT + 0x3ff00000, 0x201c2010, 0x20042004, 0x27742004, 0x29742944, 0x27742944, 0x20042004, 0x00003ffc, // ICON_FILETYPE_3D + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x24242244, 0x24242814, 0x20042244, 0x00003ffc, // ICON_FILETYPE_XML + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x21042f04, 0x21042104, 0x20042f04, 0x00003ffc, // ICON_FILETYPE_C + 0x3ff00000, 0x201c2010, 0x23842004, 0x2bf42a04, 0x2fd42814, 0x21c42054, 0x20042004, 0x00003ffc, // ICON_FILETYPE_PYTHON + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x22842ee4, 0x28a42e84, 0x20042e64, 0x00003ffc, // ICON_FILETYPE_JS + 0x3ff00000, 0x241c2010, 0x2a8c3104, 0x28242454, 0x2ed42004, 0x2a542a54, 0x20042ed4, 0x00003ffc, // ICON_FILETYPE_ICON + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_257 +}; + +// NOTE: A pointer to current icons array should be defined +static unsigned int *guiIconsPtr = guiIcons; + +#endif // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS + +#ifndef RAYGUI_ICON_SIZE + #define RAYGUI_ICON_SIZE 0 +#endif + +// WARNING: Those values define the total size of the style data array, +// if changed, previous saved styles could become incompatible +#define RAYGUI_MAX_CONTROLS 16 // Maximum number of controls +#define RAYGUI_MAX_PROPS_BASE 16 // Maximum number of base properties +#define RAYGUI_MAX_PROPS_EXTENDED 8 // Maximum number of extended properties + +//---------------------------------------------------------------------------------- +// Module Types and Structures Definition +//---------------------------------------------------------------------------------- +// Gui control property style color element +typedef enum { BORDER = 0, BASE, TEXT, OTHER } GuiPropertyElement; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +static GuiState guiState = STATE_NORMAL; // Gui global state, if !STATE_NORMAL, forces defined state + +static Font guiFont = { 0 }; // Gui current font (WARNING: highly coupled to raylib) +static char guiFontName[32] = { 0 }; // Gui font filename, can be loaded from .rgs (Version: >=600) +static bool guiLocked = false; // Gui lock state (no inputs processed) +static float guiAlpha = 1.0f; // Gui controls transparency + +static unsigned int guiIconScale = 1; // Gui icon default scale (if icons enabled) +static unsigned int guiIconFontOffsetY = 0; // Gui icon font atlas offset (if icons backed) + +static bool guiTooltip = false; // Tooltip enabled/disabled +static const char *guiTooltipPtr = NULL; // Tooltip string pointer (string provided by user) + +static bool guiControlExclusiveMode = false; // Gui control exclusive mode (no inputs processed except current control) +static Rectangle guiControlExclusiveRec = { 0 }; // Gui control exclusive bounds rectangle, used as an unique identifier + +static int textBoxCursorIndex = 0; // Cursor index, shared by all GuiTextBox*() +//static int blinkCursorFrameCounter = 0; // Frame counter for cursor blinking +static int autoCursorCounter = 0; // Frame counter for automatic repeated cursor movement on key-down (cooldown and delay) + +//---------------------------------------------------------------------------------- +// Style data array for all gui style properties (allocated on data segment by default) +// +// NOTE 1: First set of BASE properties are generic to all controls but could be individually +// overwritten per control, first set of EXTENDED properties are generic to all controls and +// can not be overwritten individually but custom EXTENDED properties can be used by control +// +// NOTE 2: A new style set could be loaded over this array using GuiLoadStyle(), +// but default gui style could always be recovered with GuiLoadStyleDefault() +// +// guiStyle size is by default: 16*(16 + 8) = 384*4 = 1536 bytes = 1.5 KB +//---------------------------------------------------------------------------------- +static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)] = { 0 }; + +static bool guiStyleLoaded = false; // Style loaded flag for lazy style initialization + +//---------------------------------------------------------------------------------- +// Standalone Mode Functions Declaration +// +// NOTE: raygui depend on some raylib input and drawing functions +// To use raygui as standalone library, below functions must be defined by the user +//---------------------------------------------------------------------------------- +#if defined(RAYGUI_STANDALONE) + +#define KEY_RIGHT 262 +#define KEY_LEFT 263 +#define KEY_DOWN 264 +#define KEY_UP 265 +#define KEY_BACKSPACE 259 +#define KEY_ENTER 257 + +#define MOUSE_LEFT_BUTTON 0 + +// Input required functions +//------------------------------------------------------------------------------- +static Vector2 GetMousePosition(void); +static float GetMouseWheelMove(void); +static bool IsMouseButtonDown(int button); +static bool IsMouseButtonPressed(int button); +static bool IsMouseButtonReleased(int button); + +static bool IsKeyDown(int key); +static bool IsKeyPressed(int key); +static int GetCharPressed(void); // -- GuiTextBox(), GuiValueBox() +//------------------------------------------------------------------------------- + +// Drawing required functions +//------------------------------------------------------------------------------- +static void DrawRectangle(int x, int y, int width, int height, Color color); // -- GuiDrawRectangle() +static void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // -- GuiColorPicker() +//------------------------------------------------------------------------------- + +// Text required functions +//------------------------------------------------------------------------------- +static Font GetFontDefault(void); // -- GuiLoadStyleDefault() +static Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // -- GuiLoadStyle(), load font + +static Texture2D LoadTextureFromImage(Image image); // -- GuiLoadStyle(), required to load texture from embedded font atlas image +static void SetShapesTexture(Texture2D tex, Rectangle rec); // -- GuiLoadStyle(), required to set shapes rec to font white rec (optimization) + +static char *LoadFileText(const char *fileName); // -- GuiLoadStyle(), required to load charset data +static void UnloadFileText(char *text); // -- GuiLoadStyle(), required to unload charset data + +static const char *GetDirectoryPath(const char *filePath); // -- GuiLoadStyle(), required to find charset/font file from text .rgs + +static int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle(), required to load required font codepoints list +static void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list + +static unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle() + +static Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font +//------------------------------------------------------------------------------- + +// raylib functions already implemented in raygui +//------------------------------------------------------------------------------- +static Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value +static Color Fade(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f +static int ColorToInt(Color color); // Returns hexadecimal value for a Color +static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle +static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed' +static int TextToInteger(const char *text); // Get integer value from text +static float TextToFloat(const char *text); // Get float value from text + +static int GetCodepointNext(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded text +static const char *CodepointToUTF8(int codepoint, int *byteSize); // Encode codepoint into UTF-8 text (char array size returned as parameter) +//------------------------------------------------------------------------------- + +#endif // RAYGUI_STANDALONE + +//---------------------------------------------------------------------------------- +// Module Internal Functions Declaration +//---------------------------------------------------------------------------------- +static int GetLineWidth(const char *text); // Get text line width (stops at '\n' or '\0') +static Rectangle GetTextBounds(int control, Rectangle bounds); // Get text bounds considering control bounds +static const char *GetTextIcon(const char *text, int *iconId); // Get text icon if provided and move text cursor + +static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint); // Gui draw text using default font +static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // Gui draw rectangle using default raygui style + +static char **GuiTextSplit(const char *text, char delimiter, int *count); // Split controls text into multiple strings +static Vector3 ConvertHSVtoRGB(Vector3 hsv); // Convert color data from HSV to RGB +static Vector3 ConvertRGBtoHSV(Vector3 rgb); // Convert color data from RGB to HSV + +static void GuiTooltip(Rectangle controlRec); // Draw tooltip using control rec position +static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel() +static int GuiFontIconBaking(Image *imFont, Font font, Rectangle *whiteRec); // Update font image atlas to append raygui icons + +static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor + +//---------------------------------------------------------------------------------- +// Gui Setup Functions Definition +//---------------------------------------------------------------------------------- +// Enable gui global state +// NOTE: Checking for STATE_DISABLED to avoid messing custom global state setups +void GuiEnable(void) { if (guiState == STATE_DISABLED) guiState = STATE_NORMAL; } + +// Disable gui global state +// NOTE: Checking for STATE_NORMAL to avoid messing custom global state setups +void GuiDisable(void) { if (guiState == STATE_NORMAL) guiState = STATE_DISABLED; } + +// Lock gui global state +void GuiLock(void) { guiLocked = true; } + +// Unlock gui global state +void GuiUnlock(void) { guiLocked = false; } + +// Check if gui is locked (global state) +bool GuiIsLocked(void) { return guiLocked; } + +// Set gui controls alpha global state +void GuiSetAlpha(float alpha) +{ + if (alpha < 0.0f) alpha = 0.0f; + else if (alpha > 1.0f) alpha = 1.0f; + + guiAlpha = alpha; +} + +// Set gui state (global state) +void GuiSetState(int state) { guiState = (GuiState)state; } + +// Get gui state (global state) +int GuiGetState(void) { return guiState; } + +// Set custom gui font +// NOTE: Font loading/unloading is external to raygui +void GuiSetFont(Font font) +{ + if (font.texture.id > 0) + { + // NOTE: If a font is tried to be set but default style has not been lazily loaded first, + // it will be overwritten, so default style loading needs to be forced first + if (!guiStyleLoaded) GuiLoadStyleDefault(); + + guiFont = font; + } +} + +// Get custom gui font +Font GuiGetFont(void) +{ + return guiFont; +} + +// Set control style property value +void GuiSetStyle(int control, int property, int value) +{ + if (!guiStyleLoaded) GuiLoadStyleDefault(); + guiStyle[control*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property] = value; + + // Default properties are propagated to all controls + if ((control == 0) && (property < RAYGUI_MAX_PROPS_BASE)) + { + for (int i = 1; i < RAYGUI_MAX_CONTROLS; i++) guiStyle[i*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property] = value; + } +} + +// Get control style property value +int GuiGetStyle(int control, int property) +{ + if (!guiStyleLoaded) GuiLoadStyleDefault(); + return guiStyle[control*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property]; +} + +//---------------------------------------------------------------------------------- +// Gui Controls Functions Definition +//---------------------------------------------------------------------------------- + +// Window Box control +int GuiWindowBox(Rectangle bounds, const char *title) +{ + // Window title bar height (including borders) + // NOTE: This define is also used by GuiMessageBox() and GuiTextInputBox() + #if !defined(RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT) + #define RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT 24 + #endif + + #if !defined(RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT) + #define RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT 18 + #endif + + int result = RESULT_NONE; + //GuiState state = guiState; + + int statusBarHeight = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT; + int statusBorderWidth = GuiGetStyle(STATUSBAR, BORDER_WIDTH); + + Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)statusBarHeight }; + if (bounds.height < statusBarHeight*2.0f) bounds.height = statusBarHeight*2.0f; + + const float vPadding = statusBarHeight/2.0f - RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT/2.0f; + Rectangle windowPanel = { bounds.x, bounds.y + (float)statusBarHeight - (float)statusBorderWidth, bounds.width, bounds.height - (float)statusBarHeight + (float)statusBorderWidth }; + Rectangle closeButtonRec = { statusBar.x + statusBar.width - (float)statusBorderWidth - RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT - vPadding, + statusBar.y + vPadding, RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT, RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT }; + + // Update control + //-------------------------------------------------------------------- + // NOTE: Logic is directly managed by button + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiPanel(windowPanel, NULL); // Draw window base + + int tempTextAlignment = GuiGetStyle(STATUSBAR, TEXT_ALIGNMENT); + GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiStatusBar(statusBar, title); // Draw window header as status bar + GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, tempTextAlignment); + + // Draw window close button + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 1); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); +#if defined(RAYGUI_NO_ICONS) + result = GuiButton(closeButtonRec, "x"); +#else + result = GuiButton(closeButtonRec, GuiIconText(ICON_CROSS_SMALL, NULL)); +#endif + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); + //-------------------------------------------------------------------- + + return result; +} + +// Group Box control with text name +int GuiGroupBox(Rectangle bounds, const char *text) +{ + #if !defined(RAYGUI_GROUPBOX_LINE_THICK) + #define RAYGUI_GROUPBOX_LINE_THICK 1 + #endif + + int result = RESULT_NONE; + GuiState state = guiState; + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, RAYGUI_GROUPBOX_LINE_THICK }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR))); + + GuiLine(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y - GuiGetStyle(DEFAULT, TEXT_SIZE)/2, bounds.width, (float)GuiGetStyle(DEFAULT, TEXT_SIZE) }, text); + //-------------------------------------------------------------------- + + return result; +} + +// Line control +int GuiLine(Rectangle bounds, const char *text) +{ + #if !defined(RAYGUI_LINE_MARGIN_TEXT) + #define RAYGUI_LINE_MARGIN_TEXT 12 + #endif + #if !defined(RAYGUI_LINE_TEXT_PADDING) + #define RAYGUI_LINE_TEXT_PADDING 4 + #endif + + int result = RESULT_NONE; + GuiState state = guiState; + + Color color = GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)); + + // Draw control + //-------------------------------------------------------------------- + if (text == NULL) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height/2, bounds.width, 1 }, 0, BLANK, color); + else + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GuiGetTextWidth(text) + 2; + textBounds.height = bounds.height; + textBounds.x = bounds.x + RAYGUI_LINE_MARGIN_TEXT; + textBounds.y = bounds.y; + + // Draw line with embedded text label: "--- text --------------" + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height/2, RAYGUI_LINE_MARGIN_TEXT - RAYGUI_LINE_TEXT_PADDING, 1 }, 0, BLANK, color); + GuiDrawText(text, textBounds, TEXT_ALIGN_LEFT, color); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + 12 + textBounds.width + 4, bounds.y + bounds.height/2, bounds.width - textBounds.width - RAYGUI_LINE_MARGIN_TEXT - RAYGUI_LINE_TEXT_PADDING, 1 }, 0, BLANK, color); + } + //-------------------------------------------------------------------- + + return result; +} + +// Panel control +int GuiPanel(Rectangle bounds, const char *text) +{ + #if !defined(RAYGUI_PANEL_BORDER_WIDTH) + #define RAYGUI_PANEL_BORDER_WIDTH 1 + #endif + + int result = RESULT_NONE; + GuiState state = guiState; + + // Text will be drawn as a header bar (if provided) + Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT }; + if ((text != NULL) && (bounds.height < RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f)) bounds.height = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f; + + if (text != NULL) + { + // Move panel bounds after the header bar + bounds.y += (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1; + bounds.height -= (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1; + } + + // Draw control + //-------------------------------------------------------------------- + if (text != NULL) result = GuiStatusBar(statusBar, text); // Draw panel header as status bar + + GuiDrawRectangle(bounds, RAYGUI_PANEL_BORDER_WIDTH, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)), + GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BASE_COLOR_DISABLED : (int)BACKGROUND_COLOR))); + //-------------------------------------------------------------------- + + return result; +} + +// Scroll Panel control +int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view) +{ + #define RAYGUI_MIN_SCROLLBAR_WIDTH 40 + #define RAYGUI_MIN_SCROLLBAR_HEIGHT 40 + #define RAYGUI_MIN_MOUSE_WHEEL_SPEED 20 + + int result = RESULT_NONE; + GuiState state = guiState; + + Rectangle temp = { 0 }; + if (view == NULL) view = &temp; + + Vector2 scrollPos = { 0.0f, 0.0f }; + if (scroll != NULL) scrollPos = *scroll; + + // Text will be drawn as a header bar (if provided) + Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT }; + if (bounds.height < RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f) bounds.height = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f; + + if (text != NULL) + { + // Move panel bounds after the header bar + bounds.y += (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1; + bounds.height -= (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + 1; + } + + bool hasHorizontalScrollBar = (content.width > bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false; + bool hasVerticalScrollBar = (content.height > bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false; + + // Recheck to account for the other scrollbar being visible + if (!hasHorizontalScrollBar) hasHorizontalScrollBar = (hasVerticalScrollBar && (content.width > (bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false; + if (!hasVerticalScrollBar) hasVerticalScrollBar = (hasHorizontalScrollBar && (content.height > (bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false; + + int horizontalScrollBarWidth = hasHorizontalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0; + int verticalScrollBarWidth = hasVerticalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0; + Rectangle horizontalScrollBar = { + (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + verticalScrollBarWidth : (float)bounds.x) + GuiGetStyle(DEFAULT, BORDER_WIDTH), + (float)bounds.y + bounds.height - horizontalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH), + (float)bounds.width - verticalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH), + (float)horizontalScrollBarWidth + }; + Rectangle verticalScrollBar = { + (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)bounds.x + bounds.width - verticalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH)), + (float)bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), + (float)verticalScrollBarWidth, + (float)bounds.height - horizontalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) + }; + + // Make sure scroll bars have a minimum width/height + if (horizontalScrollBar.width < RAYGUI_MIN_SCROLLBAR_WIDTH) horizontalScrollBar.width = RAYGUI_MIN_SCROLLBAR_WIDTH; + if (verticalScrollBar.height < RAYGUI_MIN_SCROLLBAR_HEIGHT) verticalScrollBar.height = RAYGUI_MIN_SCROLLBAR_HEIGHT; + + // Calculate view area (area without the scrollbars) + *view = (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? + RAYGUI_CLITERAL(Rectangle){ bounds.x + verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth, bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth } : + RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth, bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth }; + + // Clip view area to the actual content size + if (view->width > content.width) view->width = content.width; + if (view->height > content.height) view->height = content.height; + + float horizontalMin = hasHorizontalScrollBar? ((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH); + float horizontalMax = hasHorizontalScrollBar? content.width - bounds.width + (float)verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH) - (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)verticalScrollBarWidth : 0) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); + float verticalMin = -(float)GuiGetStyle(DEFAULT, BORDER_WIDTH); + float verticalMax = hasVerticalScrollBar? content.height - bounds.height + (float)horizontalScrollBarWidth + (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check button state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + +#if defined(SUPPORT_SCROLLBAR_KEY_INPUT) + if (hasHorizontalScrollBar) + { + if (GUI_KEY_DOWN(KEY_RIGHT)) scrollPos.x -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + if (GUI_KEY_DOWN(KEY_LEFT)) scrollPos.x += GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + } + + if (hasVerticalScrollBar) + { + if (GUI_KEY_DOWN(KEY_DOWN)) scrollPos.y -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + if (GUI_KEY_DOWN(KEY_UP)) scrollPos.y += GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + } +#endif + float scrollDelta = GUI_SCROLL_DELTA; + + // Set scrolling speed with mouse wheel based on ratio between bounds and content + Vector2 scrollSpeed = { content.width/bounds.width, content.height/bounds.height }; + if (scrollSpeed.x < RAYGUI_MIN_MOUSE_WHEEL_SPEED) scrollSpeed.x = RAYGUI_MIN_MOUSE_WHEEL_SPEED; + if (scrollSpeed.y < RAYGUI_MIN_MOUSE_WHEEL_SPEED) scrollSpeed.y = RAYGUI_MIN_MOUSE_WHEEL_SPEED; + + // Horizontal and vertical scrolling with mouse wheel + if (hasHorizontalScrollBar && (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_LEFT_SHIFT))) scrollPos.x += scrollDelta*scrollSpeed.x; + else scrollPos.y += scrollDelta*scrollSpeed.y; // Vertical scroll + } + } + + // Normalize scroll values + if (scrollPos.x > -horizontalMin) scrollPos.x = -horizontalMin; + if (scrollPos.x < -horizontalMax) scrollPos.x = -horizontalMax; + if (scrollPos.y > -verticalMin) scrollPos.y = -verticalMin; + if (scrollPos.y < -verticalMax) scrollPos.y = -verticalMax; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (text != NULL) result = GuiStatusBar(statusBar, text); // Draw panel header as status bar + + GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background + + // Save size of the scrollbar slider + const int slider = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); + + // Draw horizontal scrollbar if visible + if (hasHorizontalScrollBar) + { + // Change scrollbar slider size to show the diff in size between the content width and the widget width + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)(((bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth)/(int)content.width)*((int)bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth))); + scrollPos.x = (float)-GuiScrollBar(horizontalScrollBar, (int)-scrollPos.x, (int)horizontalMin, (int)horizontalMax); + } + else scrollPos.x = 0.0f; + + // Draw vertical scrollbar if visible + if (hasVerticalScrollBar) + { + // Change scrollbar slider size to show the diff in size between the content height and the widget height + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)(((bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth)/(int)content.height)*((int)bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth))); + scrollPos.y = (float)-GuiScrollBar(verticalScrollBar, (int)-scrollPos.y, (int)verticalMin, (int)verticalMax); + } + else scrollPos.y = 0.0f; + + // Draw detail corner rectangle if both scroll bars are visible + if (hasHorizontalScrollBar && hasVerticalScrollBar) + { + Rectangle corner = { (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH) + 2) : (horizontalScrollBar.x + horizontalScrollBar.width + 2), verticalScrollBar.y + verticalScrollBar.height + 2, (float)horizontalScrollBarWidth - 4, (float)verticalScrollBarWidth - 4 }; + GuiDrawRectangle(corner, 0, BLANK, GetColor(GuiGetStyle(LISTVIEW, TEXT + (state*3)))); + } + + // Draw scrollbar lines depending on current state + GuiDrawRectangle(bounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + (state*3))), BLANK); + + // Set scrollbar slider size back to the way it was before + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, slider); + //-------------------------------------------------------------------- + + if (scroll != NULL) *scroll = scrollPos; + + return result; +} + +// Label control +int GuiLabel(Rectangle bounds, const char *text) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + // Update control + //-------------------------------------------------------------------- + //... + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + +// Button control, returns true when clicked +int GuiButton(Rectangle bounds, const char *text) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check button state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(BUTTON, BORDER_WIDTH), GetColor(GuiGetStyle(BUTTON, BORDER + (state*3))), GetColor(GuiGetStyle(BUTTON, BASE + (state*3)))); + GuiDrawText(text, GetTextBounds(BUTTON, bounds), GuiGetStyle(BUTTON, TEXT_ALIGNMENT), GetColor(GuiGetStyle(BUTTON, TEXT + (state*3)))); + + if (state == STATE_FOCUSED) GuiTooltip(bounds); + //------------------------------------------------------------------ + + return result; +} + +// Label button control +int GuiLabelButton(Rectangle bounds, const char *text) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + // NOTE: Force bounds.width to be all text + float textWidth = (float)GuiGetTextWidth(text); + if ((bounds.width - 2*GuiGetStyle(LABEL, BORDER_WIDTH) - 2*GuiGetStyle(LABEL, TEXT_PADDING)) < textWidth) bounds.width = textWidth + 2*GuiGetStyle(LABEL, BORDER_WIDTH) + 2*GuiGetStyle(LABEL, TEXT_PADDING) + 2; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check checkbox state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + +// Toggle Button control +int GuiToggle(Rectangle bounds, const char *text, bool *active) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + bool temp = false; + if (active == NULL) active = &temp; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check toggle button state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else if (GUI_BUTTON_RELEASED) + { + state = STATE_NORMAL; + *active = !(*active); + + result = RESULT_CHANGED; + } + else state = STATE_FOCUSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state == STATE_NORMAL) + { + GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, ((*active)? BORDER_COLOR_PRESSED : (BORDER + state*3)))), GetColor(GuiGetStyle(TOGGLE, ((*active)? BASE_COLOR_PRESSED : (BASE + state*3))))); + GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TOGGLE, ((*active)? TEXT_COLOR_PRESSED : (TEXT + state*3))))); + } + else + { + GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, BORDER + state*3)), GetColor(GuiGetStyle(TOGGLE, BASE + state*3))); + GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TOGGLE, TEXT + state*3))); + } + + if (state == STATE_FOCUSED) GuiTooltip(bounds); + //-------------------------------------------------------------------- + + return result; +} + +// Toggle Group control +int GuiToggleGroup(Rectangle bounds, const char *text, int *active) +{ + int result = RESULT_NONE; + + #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE) + #define RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE 256 + #endif + + // One toggle group item text + static char itemText[RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE] = { 0 }; + memset(itemText, 0, RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE); + + int temp = 0; + int prevActive = (active == NULL)? 0 : *active; + if (active == NULL) active = &temp; + + bool toggle = false; // Required for individual toggles + + const char *textPtr = text; + bool itemReady = false; + float initBoundsX = bounds.x; + float initBoundsY = bounds.y; + + if (GuiGetStyle(TOGGLE, GROUP_WIDTH_FULL)) + { + // Calculate item width considring all horizontal items + // NOTE: bounds.height still considers individual items height + int itemCount = 1; + for (int c = 0; textPtr[c] != '\0'; c++) { if (textPtr[c] == ';') itemCount++; } + bounds.width /= itemCount; + } + + // Text parsing needed to consider potential row and col entries (vertical/horizontal layout) + // when '\n' found move vertically next toggle, when ';' found move horizontally + for (int c = 0, k = 0, itemIndex = 0, row = 0, col = 0, exit = 0; exit == 0; c++) + { + // Process text to get items one by one + // NOTE: Setting columns and rows index properly + if (textPtr[c] == '\n') + { + row++; + col = 0; + itemReady = true; + } + else if (textPtr[c] == ';') + { + col++; + itemReady = true; + } + else if (textPtr[c] == '\0') + { + itemReady = true; + exit = 1; + } + else + { + itemText[k] = textPtr[c]; + k++; + } + + if (itemReady) + { + // When a next item is ready, draw its toggle + if (itemIndex == (*active)) + { + toggle = true; + GuiToggle(bounds, itemText, &toggle); + } + else + { + toggle = false; + GuiToggle(bounds, itemText, &toggle); + if (toggle) *active = itemIndex; + } + + // Calculate next item position + bounds.x = initBoundsX + col*(bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING)); + bounds.y = initBoundsY + row*(bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING)); + + itemIndex++; + itemReady = false; + memset(itemText, 0, k + 1); + k = 0; + } + } + + if (prevActive != *active) result = RESULT_CHANGED; + + return result; +} + +// Toggle Slider control extended +int GuiToggleSlider(Rectangle bounds, const char *text, int *active) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + int temp = 0; + int prevActive = (active == NULL)? 0 : *active; + if (active == NULL) active = &temp; + + // Get substrings items from text (items pointers) + int itemCount = 0; + char **items = NULL; + + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount); + + Rectangle slider = { + 0, // Calculated later depending on the active toggle + bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING), + (bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - (itemCount + 1)*GuiGetStyle(SLIDER, SLIDER_PADDING))/itemCount, + bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) }; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else if (GUI_BUTTON_RELEASED) + { + state = STATE_PRESSED; + (*active)++; + result = 1; + } + else state = STATE_FOCUSED; + } + + if ((*active) && (state != STATE_FOCUSED)) state = STATE_PRESSED; + } + + if (*active >= itemCount) *active = 0; + slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH) + (*active + 1)*GuiGetStyle(SLIDER, SLIDER_PADDING) + (*active)*slider.width; + + if (prevActive != *active) result = RESULT_CHANGED; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, BORDER + (state*3))), + GetColor(GuiGetStyle(TOGGLE, BASE_COLOR_NORMAL))); + + // Draw internal slider + if (state == STATE_NORMAL) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED))); + else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_FOCUSED))); + else if (state == STATE_PRESSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED))); + + // Draw text in slider + if (text != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GuiGetTextWidth(text); + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = slider.x + slider.width/2 - textBounds.width/2; + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(items[*active], textBounds, GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TOGGLE, TEXT + (state*3))), guiAlpha)); + } + //-------------------------------------------------------------------- + + return result; +} + +// Check Box control, returns 1 when state changed +int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + bool temp = false; + if (checked == NULL) checked = &temp; + + Rectangle textBounds = { 0 }; + + if (text != NULL) + { + textBounds.width = (float)GuiGetTextWidth(text) + 2; + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + if (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(CHECKBOX, TEXT_PADDING); + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + Rectangle totalBounds = { + (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT)? textBounds.x : bounds.x, + bounds.y, + bounds.width + textBounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING), + bounds.height, + }; + + // Check checkbox state + if (CheckCollisionPointRec(mousePoint, totalBounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) + { + *checked = !(*checked); + + result = RESULT_CHANGED; + } + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(CHECKBOX, BORDER_WIDTH), GetColor(GuiGetStyle(CHECKBOX, BORDER + (state*3))), BLANK); + + if (*checked) + { + Rectangle check = { bounds.x + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING), + bounds.y + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING), + bounds.width - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING)), + bounds.height - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING)) }; + GuiDrawRectangle(check, 0, BLANK, GetColor(GuiGetStyle(CHECKBOX, TEXT + state*3))); + } + + GuiDrawText(text, textBounds, (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + +// Combo Box control +int GuiComboBox(Rectangle bounds, const char *text, int *active) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + int temp = 0; + int prevActive = (active == NULL)? 0 : *active; + if (active == NULL) active = &temp; + + bounds.width -= (GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH) + GuiGetStyle(COMBOBOX, COMBO_BUTTON_SPACING)); + + Rectangle selector = { (float)bounds.x + bounds.width + GuiGetStyle(COMBOBOX, COMBO_BUTTON_SPACING), + (float)bounds.y, (float)GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH), (float)bounds.height }; + + // Get substrings items from text (items pointers, lengths and count) + int itemCount = 0; + char **items = GuiTextSplit(text, ';', &itemCount); + + if (*active < 0) *active = 0; + else if (*active > (itemCount - 1)) *active = itemCount - 1; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && (itemCount > 1) && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (CheckCollisionPointRec(mousePoint, bounds) || + CheckCollisionPointRec(mousePoint, selector)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + + if (GUI_BUTTON_PRESSED) + { + *active += 1; + if (*active >= itemCount) *active = 0; // Cyclic combobox + } + } + } + + if (prevActive != *active) result = RESULT_CHANGED; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + // Draw combo box main + GuiDrawRectangle(bounds, GuiGetStyle(COMBOBOX, BORDER_WIDTH), GetColor(GuiGetStyle(COMBOBOX, BORDER + (state*3))), GetColor(GuiGetStyle(COMBOBOX, BASE + (state*3)))); + GuiDrawText(items[*active], GetTextBounds(COMBOBOX, bounds), GuiGetStyle(COMBOBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(COMBOBOX, TEXT + (state*3)))); + + // Draw selector using a custom button + // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 1); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + + GuiButton(selector, TextFormat("%i/%i", *active + 1, itemCount)); + + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign); + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + //-------------------------------------------------------------------- + + return result; +} + +// Dropdown Box control +// NOTE: Returns mouse click +int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + int temp = 0; + int prevActive = (active == NULL)? 0 : *active; + if (active == NULL) active = &temp; + + int itemSelected = *active; + int itemFocused = -1; + + int direction = 0; // Dropdown box open direction: down (default) + if (GuiGetStyle(DROPDOWNBOX, DROPDOWN_ROLL_UP) == 1) direction = 1; // Up + + // Get substrings items from text (items pointers, lengths and count) + int itemCount = 0; + char **items = GuiTextSplit(text, ';', &itemCount); + + Rectangle boundsOpen = bounds; + boundsOpen.height = (itemCount + 1)*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + if (direction == 1) boundsOpen.y -= itemCount*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)) + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING); + + Rectangle itemBounds = bounds; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && (editMode || !guiLocked) && (itemCount > 1) && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (editMode) + { + state = STATE_PRESSED; + + // Check if mouse has been pressed or released outside limits + if (!CheckCollisionPointRec(mousePoint, boundsOpen)) + { + if (GUI_BUTTON_PRESSED || GUI_BUTTON_RELEASED) result = 1; + } + + // Check if already selected item has been pressed again + if (CheckCollisionPointRec(mousePoint, bounds) && GUI_BUTTON_PRESSED) result = 1; + + // Check focused and selected item + for (int i = 0; i < itemCount; i++) + { + // Update item rectangle y position for next item + if (direction == 0) itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + else itemBounds.y -= (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + + if (CheckCollisionPointRec(mousePoint, itemBounds)) + { + itemFocused = i; + if (GUI_BUTTON_RELEASED) + { + itemSelected = i; + result = 1; // Item selected + } + break; + } + } + + itemBounds = bounds; + } + else + { + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_PRESSED) + { + result = 1; + state = STATE_PRESSED; + } + else state = STATE_FOCUSED; + } + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (editMode) GuiPanel(boundsOpen, NULL); + + GuiDrawRectangle(bounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER + state*3)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE + state*3))); + GuiDrawText(items[itemSelected], GetTextBounds(DROPDOWNBOX, bounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + state*3))); + + if (editMode) + { + // Draw visible items + for (int i = 0; i < itemCount; i++) + { + // Update item rectangle y position for next item + if (direction == 0) itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + else itemBounds.y -= (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + + if (i == itemSelected) + { + GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_PRESSED))); + GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_PRESSED))); + } + else if (i == itemFocused) + { + GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_FOCUSED))); + GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_FOCUSED))); + } + else GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_NORMAL))); + } + } + + if (!GuiGetStyle(DROPDOWNBOX, DROPDOWN_ARROW_HIDDEN)) + { + // Draw arrows (using icon if available) +#if defined(RAYGUI_NO_ICONS) + GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); +#else + GuiDrawText(direction? GuiIconText(ICON_ARROW_UP_FILL, NULL) : GuiIconText(ICON_ARROW_DOWN_FILL, NULL), + RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); // ICON_ARROW_DOWN_FILL +#endif + } + //-------------------------------------------------------------------- + + *active = itemSelected; + + if (prevActive != *active) result = RESULT_CHANGED; + + return result; +} + +// Text Box control +// NOTE: Returns true on ENTER pressed (useful for data validation) +int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) +{ + #if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN) + #define RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN 20 // Frames to wait for autocursor movement + #endif + #if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) + #define RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY 1 // Frames delay for autocursor movement + #endif + + int result = RESULT_NONE; + GuiState state = guiState; + + bool multiline = false; + int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); + + Rectangle textBounds = GetTextBounds(TEXTBOX, bounds); + int textLength = (text != NULL)? (int)strlen(text) : 0; // Get current text length + int thisCursorIndex = textBoxCursorIndex; + if (thisCursorIndex > textLength) thisCursorIndex = textLength; + int textWidth = GuiGetTextWidth(text) - GuiGetTextWidth(text + thisCursorIndex); + int textIndexOffset = 0; // Text index offset to start drawing in the box + + // Cursor rectangle + // NOTE: Position X value should be updated + Rectangle cursor = { + textBounds.x + textWidth + GuiGetStyle(DEFAULT, TEXT_SPACING), + textBounds.y + textBounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE), + 2, + (float)GuiGetStyle(DEFAULT, TEXT_SIZE)*2 + }; + + if (cursor.height >= bounds.height) cursor.height = bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2; + if (cursor.y < (bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH))) cursor.y = bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH); + + // Mouse cursor rectangle + // NOTE: Initialized outside of screen + Rectangle mouseCursor = cursor; + mouseCursor.x = -1; + mouseCursor.width = 1; + + // Blink-cursor frame counter + //if (!autoCursorMode) blinkCursorFrameCounter++; + //else blinkCursorFrameCounter = 0; + + // Update control + //-------------------------------------------------------------------- + // WARNING: Text editing is only supported under certain conditions: + if ((state != STATE_DISABLED) && // Control not disabled + !GuiGetStyle(TEXTBOX, TEXT_READONLY) && // TextBox not on read-only mode + !guiLocked && // Gui not locked + !guiControlExclusiveMode && // No gui slider on dragging + (wrapMode == TEXT_WRAP_NONE)) // No wrap mode + { + Vector2 mousePosition = GUI_POINTER_POSITION; + + if (editMode) + { + // GLOBAL: Auto-cursor movement logic + // NOTE: Keystrokes are handled repeatedly when button is held down for some time + if (GUI_KEY_DOWN(KEY_LEFT) || GUI_KEY_DOWN(KEY_RIGHT) || + GUI_KEY_DOWN(KEY_UP) || GUI_KEY_DOWN(KEY_DOWN) || + GUI_KEY_DOWN(KEY_BACKSPACE) || GUI_KEY_DOWN(KEY_DELETE)) autoCursorCounter++; + else autoCursorCounter = 0; + + bool autoCursorShouldTrigger = (autoCursorCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN) && ((autoCursorCounter % RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0); + + state = STATE_PRESSED; + + if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength; + + // If text does not fit in the textbox and current cursor position is out of bounds, + // adding an index offset to text for drawing only what requires depending on cursor + while (textWidth >= textBounds.width) + { + int nextCodepointSize = 0; + GetCodepointNext(text + textIndexOffset, &nextCodepointSize); + + textIndexOffset += nextCodepointSize; + + textWidth = GuiGetTextWidth(text + textIndexOffset) - GuiGetTextWidth(text + textBoxCursorIndex); + } + + int codepoint = GUI_INPUT_KEY; // Get Unicode codepoint + if (multiline && GUI_KEY_PRESSED(KEY_ENTER)) codepoint = (int)'\n'; + + // Encode codepoint as UTF-8 + int codepointSize = 0; + const char *charEncoded = CodepointToUTF8(codepoint, &codepointSize); + + // Handle text paste action + if (GUI_KEY_PRESSED(KEY_V) && (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) + { + const char *pasteText = GetClipboardText(); + if (pasteText != NULL) + { + int pasteLength = 0; + int pasteCodepoint; + int pasteCodepointSize; + + // Count how many codepoints to copy, stopping at the first unwanted control character + while (true) + { + pasteCodepoint = GetCodepointNext(pasteText + pasteLength, &pasteCodepointSize); + if (textLength + pasteLength + pasteCodepointSize >= textSize) break; + if (!(multiline && (pasteCodepoint == (int)'\n')) && !(pasteCodepoint >= 32)) break; + pasteLength += pasteCodepointSize; + } + + if (pasteLength > 0) + { + // Move forward data from cursor position + for (int i = textLength + pasteLength; i > textBoxCursorIndex; i--) text[i] = text[i - pasteLength]; + + // Paste data in at cursor + for (int i = 0; i < pasteLength; i++) text[textBoxCursorIndex + i] = pasteText[i]; + + textBoxCursorIndex += pasteLength; + textLength += pasteLength; + text[textLength] = '\0'; + + //result = RESULT_CHANGED; + } + } + } + else if (((multiline && (codepoint == (int)'\n')) || (codepoint >= 32)) && ((textLength + codepointSize) < textSize)) + { + // Adding codepoint to text, at current cursor position + + // Move forward data from cursor position + for (int i = (textLength + codepointSize); i > textBoxCursorIndex; i--) text[i] = text[i - codepointSize]; + + // Add new codepoint in current cursor position + for (int i = 0; i < codepointSize; i++) text[textBoxCursorIndex + i] = charEncoded[i]; + + textBoxCursorIndex += codepointSize; + textLength += codepointSize; + + // Make sure text last character is EOL + text[textLength] = '\0'; + + //result = RESULT_CHANGED; + } + + // Move cursor to start + if ((textLength > 0) && GUI_KEY_PRESSED(KEY_HOME)) textBoxCursorIndex = 0; + + // Move cursor to end + if ((textLength > textBoxCursorIndex) && GUI_KEY_PRESSED(KEY_END)) textBoxCursorIndex = textLength; + + // Delete related codepoints from text, after current cursor position + if ((textLength > textBoxCursorIndex) && GUI_KEY_PRESSED(KEY_DELETE) && (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) + { + int offset = textBoxCursorIndex; + int accCodepointSize = 0; + int nextCodepointSize; + int nextCodepoint; + + // Check characters of the same type to delete (either ASCII punctuation or anything non-whitespace) + // Not using isalnum() since it only works on ASCII characters + nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); + bool puctuation = ispunct(nextCodepoint & 0xff); + while (offset < textLength) + { + if ((puctuation && !ispunct(nextCodepoint & 0xff)) || + (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff)))) break; + + offset += nextCodepointSize; + accCodepointSize += nextCodepointSize; + nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); + } + + // Check whitespace to delete (ASCII only) + while (offset < textLength) + { + if (!isspace(nextCodepoint & 0xff)) break; + + offset += nextCodepointSize; + accCodepointSize += nextCodepointSize; + nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); + } + + // Move text after cursor forward (including final null terminator) + for (int i = offset; i <= textLength; i++) text[i - accCodepointSize] = text[i]; + + textLength -= accCodepointSize; + + //result = RESULT_CHANGED; + } + else if ((textLength > textBoxCursorIndex) && (GUI_KEY_PRESSED(KEY_DELETE) || + (GUI_KEY_DOWN(KEY_DELETE) && autoCursorShouldTrigger))) + { + // Delete single codepoint from text, after current cursor position + + int nextCodepointSize = 0; + GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize); + + // Move text after cursor forward (including final null terminator) + for (int i = textBoxCursorIndex + nextCodepointSize; i <= textLength; i++) text[i - nextCodepointSize] = text[i]; + + textLength -= nextCodepointSize; + + //result = RESULT_CHANGED; + } + + // Delete related codepoints from text, before current cursor position + if ((textBoxCursorIndex > 0) && GUI_KEY_PRESSED(KEY_BACKSPACE) && + (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) + { + int offset = textBoxCursorIndex; + int accCodepointSize = 0; + int prevCodepointSize = 0; + int prevCodepoint = 0; + + // Check whitespace to delete (ASCII only) + while (offset > 0) + { + prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize); + if (!isspace(prevCodepoint & 0xff)) break; + + offset -= prevCodepointSize; + accCodepointSize += prevCodepointSize; + } + + // Check characters of the same type to delete (either ASCII punctuation or anything non-whitespace) + // Not using isalnum() since it only works on ASCII characters + bool puctuation = ispunct(prevCodepoint & 0xff); + while (offset > 0) + { + prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize); + if ((puctuation && !ispunct(prevCodepoint & 0xff)) || + (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break; + + offset -= prevCodepointSize; + accCodepointSize += prevCodepointSize; + } + + // Move text after cursor forward (including final null terminator) + for (int i = textBoxCursorIndex; i <= textLength; i++) text[i - accCodepointSize] = text[i]; + + textLength -= accCodepointSize; + textBoxCursorIndex -= accCodepointSize; + + //result = RESULT_CHANGED; + } + else if ((textBoxCursorIndex > 0) && (GUI_KEY_PRESSED(KEY_BACKSPACE) || (GUI_KEY_DOWN(KEY_BACKSPACE) && autoCursorShouldTrigger))) + { + // Delete single codepoint from text, before current cursor position + + int prevCodepointSize = 0; + + GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize); + + // Move text after cursor forward (including final null terminator) + for (int i = textBoxCursorIndex; i <= textLength; i++) text[i - prevCodepointSize] = text[i]; + + textLength -= prevCodepointSize; + textBoxCursorIndex -= prevCodepointSize; + + //result = RESULT_CHANGED; + } + + // Move cursor position with keys + if ((textBoxCursorIndex > 0) && GUI_KEY_PRESSED(KEY_LEFT) && (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) + { + int offset = textBoxCursorIndex; + //int accCodepointSize = 0; + int prevCodepointSize = 0; + int prevCodepoint = 0; + + // Check whitespace to skip (ASCII only) + while (offset > 0) + { + prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize); + if (!isspace(prevCodepoint & 0xff)) break; + + offset -= prevCodepointSize; + //accCodepointSize += prevCodepointSize; + } + + // Check characters of the same type to skip (either ASCII punctuation or anything non-whitespace) + // Not using isalnum() since it only works on ASCII characters + bool puctuation = ispunct(prevCodepoint & 0xff); + while (offset > 0) + { + prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize); + if ((puctuation && !ispunct(prevCodepoint & 0xff)) || (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break; + + offset -= prevCodepointSize; + //accCodepointSize += prevCodepointSize; + } + + textBoxCursorIndex = offset; + } + else if ((textBoxCursorIndex > 0) && (GUI_KEY_PRESSED(KEY_LEFT) || (GUI_KEY_DOWN(KEY_LEFT) && autoCursorShouldTrigger))) + { + int prevCodepointSize = 0; + GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize); + + textBoxCursorIndex -= prevCodepointSize; + } + else if ((textLength > textBoxCursorIndex) && GUI_KEY_PRESSED(KEY_RIGHT) && (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) + { + int offset = textBoxCursorIndex; + //int accCodepointSize = 0; + int nextCodepointSize; + int nextCodepoint; + + // Check characters of the same type to skip (either ASCII punctuation or anything non-whitespace) + // Not using isalnum() since it only works on ASCII characters + nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); + bool puctuation = ispunct(nextCodepoint & 0xff); + while (offset < textLength) + { + if ((puctuation && !ispunct(nextCodepoint & 0xff)) || (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff)))) break; + + offset += nextCodepointSize; + //accCodepointSize += nextCodepointSize; + nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); + } + + // Check whitespace to skip (ASCII only) + while (offset < textLength) + { + if (!isspace(nextCodepoint & 0xff)) break; + + offset += nextCodepointSize; + //accCodepointSize += nextCodepointSize; + nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); + } + + textBoxCursorIndex = offset; + } + else if ((textLength > textBoxCursorIndex) && (GUI_KEY_PRESSED(KEY_RIGHT) || (GUI_KEY_DOWN(KEY_RIGHT) && autoCursorShouldTrigger))) + { + int nextCodepointSize = 0; + GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize); + + textBoxCursorIndex += nextCodepointSize; + } + + // Move cursor position with mouse + if (CheckCollisionPointRec(mousePosition, textBounds)) + { + float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/(float)guiFont.baseSize; + int codepointIndex = 0; + float glyphWidth = 0.0f; + float widthToMouseX = 0; + int mouseCursorIndex = 0; + + for (int i = textIndexOffset; i < textLength; i += codepointSize) + { + codepoint = GetCodepointNext(&text[i], &codepointSize); + codepointIndex = GetGlyphIndex(guiFont, codepoint); + + if (guiFont.glyphs[codepointIndex].advanceX == 0) glyphWidth = ((float)guiFont.recs[codepointIndex].width*scaleFactor); + else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor); + + if (mousePosition.x <= (textBounds.x + (widthToMouseX + glyphWidth/2))) + { + mouseCursor.x = textBounds.x + widthToMouseX; + mouseCursorIndex = i; + break; + } + + widthToMouseX += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + } + + // Check if mouse cursor is at the last position + int textEndWidth = GuiGetTextWidth(text + textIndexOffset); + if (GUI_POINTER_POSITION.x >= (textBounds.x + textEndWidth - glyphWidth/2)) + { + mouseCursor.x = textBounds.x + textEndWidth; + mouseCursorIndex = textLength; + } + + // Place cursor at required index on mouse click + if ((mouseCursor.x >= 0) && GUI_BUTTON_PRESSED) + { + cursor.x = mouseCursor.x; + textBoxCursorIndex = mouseCursorIndex; + } + } + else mouseCursor.x = -1; + + // Recalculate cursor position.y depending on textBoxCursorIndex + cursor.x = bounds.x + GuiGetStyle(TEXTBOX, TEXT_PADDING) + GuiGetTextWidth(text + textIndexOffset) - GuiGetTextWidth(text + textBoxCursorIndex) + GuiGetStyle(DEFAULT, TEXT_SPACING); + //if (multiline) cursor.y = GetTextLines() + + // Finish text editing on ENTER or mouse click outside bounds + if ((!multiline && GUI_KEY_PRESSED(KEY_ENTER)) || + (!CheckCollisionPointRec(mousePosition, bounds) && GUI_BUTTON_PRESSED)) + { + textBoxCursorIndex = 0; // GLOBAL: Reset the shared cursor index + autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes + + //*editMode = false; + result = RESULT_PRESSED; + } + } + else + { + if (CheckCollisionPointRec(mousePosition, bounds)) + { + state = STATE_FOCUSED; + + if (GUI_BUTTON_PRESSED) + { + textBoxCursorIndex = textLength; // GLOBAL: Place cursor index to the end of current text + autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes + + //*editMode = true; + result = RESULT_PRESSED; + } + } + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state == STATE_PRESSED) + { + GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED))); + } + else if (state == STATE_DISABLED) + { + GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_DISABLED))); + } + else GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), BLANK); + + // Draw text considering index offset if required + // NOTE: Text index offset depends on cursor position + GuiDrawText(text + textIndexOffset, textBounds, GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3)))); + + // Draw cursor + if (editMode && !GuiGetStyle(TEXTBOX, TEXT_READONLY)) + { + //if (autoCursorMode || ((blinkCursorFrameCounter/40)%2 == 0)) + GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED))); + + // Draw mouse position cursor (if required) + if (mouseCursor.x >= 0) GuiDrawRectangle(mouseCursor, 0, BLANK, GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED))); + } + else if (state == STATE_FOCUSED) GuiTooltip(bounds); + //-------------------------------------------------------------------- + + return result; +} + +/* +// Text Box control with multiple lines and word-wrap +// NOTE: This text-box is readonly, no editing supported by default +bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode) +{ + bool pressed = false; + + GuiSetStyle(TEXTBOX, TEXT_READONLY, 1); + GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_WORD); // WARNING: If wrap mode enabled, text editing is not supported + GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_TOP); + + // TODO: Implement methods to calculate cursor position properly + pressed = GuiTextBox(bounds, text, textSize, editMode); + + GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); + GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_NONE); + GuiSetStyle(TEXTBOX, TEXT_READONLY, 0); + + return pressed; +} +*/ + +// Spinner control, returns selected value +int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) +{ + int result = 1; + GuiState state = guiState; + + int tempValue = *value; + + Rectangle valueBoxBounds = { + bounds.x + GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH) + GuiGetStyle(VALUEBOX, SPINNER_BUTTON_SPACING), + bounds.y, + bounds.width - 2*(GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH) + GuiGetStyle(VALUEBOX, SPINNER_BUTTON_SPACING)), bounds.height }; + Rectangle leftButtonBound = { (float)bounds.x, (float)bounds.y, (float)GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH), (float)bounds.height }; + Rectangle rightButtonBound = { (float)bounds.x + bounds.width - GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH), (float)bounds.y, + (float)GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH), (float)bounds.height }; + + Rectangle textBounds = { 0 }; + if (text != NULL) + { + textBounds.width = (float)GuiGetTextWidth(text) + 2; + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING); + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check spinner state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + } + } + +#if defined(RAYGUI_NO_ICONS) + if (GuiButton(leftButtonBound, "<")) tempValue--; + if (GuiButton(rightButtonBound, ">")) tempValue++; +#else + if (GuiButton(leftButtonBound, GuiIconText(ICON_ARROW_LEFT_FILL, NULL))) tempValue--; + if (GuiButton(rightButtonBound, GuiIconText(ICON_ARROW_RIGHT_FILL, NULL))) tempValue++; +#endif + + if (!editMode) + { + if (tempValue < minValue) tempValue = minValue; + if (tempValue > maxValue) tempValue = maxValue; + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + result = GuiValueBox(valueBoxBounds, NULL, &tempValue, minValue, maxValue, editMode); + + // Draw value selector custom buttons + // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, GuiGetStyle(VALUEBOX, BORDER_WIDTH)); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign); + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + + // Draw text label if provided + GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + //if (tempValue != *value) result = RESULT_CHANGED; // WARNING: Stops editing + + *value = tempValue; + + return result; +} + +// Value Box control, updates input text with numbers +int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) +{ + #if !defined(RAYGUI_VALUEBOX_MAX_CHARS) + #define RAYGUI_VALUEBOX_MAX_CHARS 32 + #endif + + int result = RESULT_NONE; + GuiState state = guiState; + + //int prevValue = *value; + char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = { 0 }; + snprintf(textValue, RAYGUI_VALUEBOX_MAX_CHARS + 1, "%i", *value); + + Rectangle textBounds = { 0 }; + if (text != NULL) + { + textBounds.width = (float)GuiGetTextWidth(text) + 2; + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING); + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + bool valueHasChanged = false; + + if (editMode) + { + state = STATE_PRESSED; + + int keyCount = (int)strlen(textValue); + + // Add or remove minus symbol + if (GUI_KEY_PRESSED(KEY_MINUS)) + { + if (textValue[0] == '-') + { + for (int i = 0 ; i < keyCount; i++) textValue[i] = textValue[i + 1]; + + keyCount--; + valueHasChanged = true; + } + else if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) + { + if (keyCount == 0) + { + textValue[0] = '0'; + textValue[1] = '\0'; + keyCount++; + } + + for (int i = keyCount ; i > -1; i--) textValue[i + 1] = textValue[i]; + + textValue[0] = '-'; + keyCount++; + valueHasChanged = true; + } + } + + // Add new digit to text value + if ((keyCount >= 0) && (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) && (GuiGetTextWidth(textValue) < bounds.width)) + { + int key = GUI_INPUT_KEY; + + // Only allow keys in range [48..57] + if ((key >= 48) && (key <= 57)) + { + textValue[keyCount] = (char)key; + keyCount++; + valueHasChanged = true; + } + } + + // Delete text + if ((keyCount > 0) && GUI_KEY_PRESSED(KEY_BACKSPACE)) + { + keyCount--; + textValue[keyCount] = '\0'; + valueHasChanged = true; + } + + if (valueHasChanged) *value = TextToInteger(textValue); + + // NOTE: Values are not clamped until user input finishes + //if (*value > maxValue) *value = maxValue; + //else if (*value < minValue) *value = minValue; + + if ((GUI_KEY_PRESSED(KEY_ENTER) || GUI_KEY_PRESSED(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && GUI_BUTTON_PRESSED)) + { + if (*value > maxValue) *value = maxValue; + else if (*value < minValue) *value = minValue; + + result = RESULT_PRESSED; + } + } + else + { + if (*value > maxValue) *value = maxValue; + else if (*value < minValue) *value = minValue; + + if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + + if (GUI_BUTTON_PRESSED) result = RESULT_PRESSED; + } + } + } + + //if (prevValue != *value) result = RESULT_CHANGED; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + Color baseColor = BLANK; + if (state == STATE_PRESSED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_PRESSED)); + else if (state == STATE_DISABLED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_DISABLED)); + + GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), baseColor); + GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3)))); + + // Draw cursor rectangle + if (editMode) + { + // NOTE: ValueBox internal text is always centered + Rectangle cursor = { bounds.x + GuiGetTextWidth(textValue)/2 + bounds.width/2 + 1, + bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + 2, + 2, bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2 - 4 }; + if (cursor.height > bounds.height) cursor.height = bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2; + GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED))); + } + + // Draw text label if provided + GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + +// Floating point Value Box control, updates input val_str with numbers +int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode) +{ + #if !defined(RAYGUI_VALUEBOX_MAX_CHARS) + #define RAYGUI_VALUEBOX_MAX_CHARS 32 + #endif + + int result = RESULT_NONE; + GuiState state = guiState; + + //float prevValue = *value; + + Rectangle textBounds = { 0 }; + if (text != NULL) + { + textBounds.width = (float)GuiGetTextWidth(text) + 2; + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING); + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + bool valueHasChanged = false; + + if (editMode) + { + state = STATE_PRESSED; + + int keyCount = (int)strlen(textValue); + + // Add or remove minus symbol + if (GUI_KEY_PRESSED(KEY_MINUS)) + { + if (textValue[0] == '-') + { + for (int i = 0; i < keyCount; i++) textValue[i] = textValue[i + 1]; + + keyCount--; + valueHasChanged = true; + } + else if (keyCount < (RAYGUI_VALUEBOX_MAX_CHARS - 1)) + { + if (keyCount == 0) + { + textValue[0] = '0'; + textValue[1] = '\0'; + keyCount++; + } + + for (int i = keyCount; i > -1; i--) textValue[i + 1] = textValue[i]; + + textValue[0] = '-'; + keyCount++; + valueHasChanged = true; + } + } + + // Only allow keys in range [48..57] + if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) + { + if (GuiGetTextWidth(textValue) < bounds.width) + { + int key = GUI_INPUT_KEY; + if (((key >= 48) && (key <= 57)) || + (key == '.') || + ((keyCount == 0) && (key == '+')) || // NOTE: Sign can only be in first position + ((keyCount == 0) && (key == '-'))) + { + textValue[keyCount] = (char)key; + keyCount++; + + valueHasChanged = true; + } + } + } + + // Pressed backspace + if (GUI_KEY_PRESSED(KEY_BACKSPACE)) + { + if (keyCount > 0) + { + keyCount--; + textValue[keyCount] = '\0'; + valueHasChanged = true; + } + } + + if (valueHasChanged) *value = TextToFloat(textValue); + + if ((GUI_KEY_PRESSED(KEY_ENTER) || GUI_KEY_PRESSED(KEY_KP_ENTER)) || + (!CheckCollisionPointRec(mousePoint, bounds) && GUI_BUTTON_PRESSED)) result = RESULT_PRESSED; + } + else + { + if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + + if (GUI_BUTTON_PRESSED) result = RESULT_PRESSED; + } + } + } + + //if (prevValue != *value) result = RESULT_CHANGED; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + Color baseColor = BLANK; + if (state == STATE_PRESSED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_PRESSED)); + else if (state == STATE_DISABLED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_DISABLED)); + + GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), baseColor); + GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3)))); + + // Draw cursor + if (editMode) + { + // NOTE: ValueBox internal text is always centered + Rectangle cursor = {bounds.x + GuiGetTextWidth(textValue)/2 + bounds.width/2 + 1, + bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4, + bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH)}; + GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED))); + } + + // Draw text label if provided + GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, + GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + +// Slider control with pro parameters +// NOTE: Other GuiSlider*() controls use this one +int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + float temp = (maxValue - minValue)/2.0f; + if (value == NULL) value = &temp; + + float prevValue = *value; + + int sliderWidth = GuiGetStyle(SLIDER, SLIDER_WIDTH); + + Rectangle slider = { bounds.x, bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING), + 0, bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) }; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (GUI_BUTTON_DOWN) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + state = STATE_PRESSED; + // Get equivalent value and slider position from mousePosition.x + *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width - sliderWidth)) + minValue; + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) + { + state = STATE_PRESSED; + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + + if (!CheckCollisionPointRec(mousePoint, slider)) + { + // Get equivalent value and slider position from mousePosition.x + *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width - sliderWidth)) + minValue; + } + } + else state = STATE_FOCUSED; + } + + if (*value > maxValue) *value = maxValue; + else if (*value < minValue) *value = minValue; + } + + // Slider bar limits check + float sliderValue = (((*value - minValue)/(maxValue - minValue))*(bounds.width - sliderWidth - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))); + if (sliderWidth > 0) // Slider + { + slider.x += sliderValue; + slider.width = (float)sliderWidth; + if (slider.x <= (bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH))) slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH); + else if ((slider.x + slider.width) >= (bounds.x + bounds.width)) slider.x = bounds.x + bounds.width - slider.width - GuiGetStyle(SLIDER, BORDER_WIDTH); + } + else if (sliderWidth == 0) // SliderBar + { + slider.x += GuiGetStyle(SLIDER, BORDER_WIDTH); + slider.width = sliderValue; + if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH); + } + + if (prevValue != *value) result = RESULT_CHANGED; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), GetColor(GuiGetStyle(SLIDER, BORDER + (state*3))), GetColor(GuiGetStyle(SLIDER, (state != STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED))); + + // Draw slider internal bar (depends on state) + if (state == STATE_NORMAL) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED))); + else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_FOCUSED))); + else if (state == STATE_PRESSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_PRESSED))); + else if (state == STATE_DISABLED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_DISABLED))); + + // Draw left/right text if provided + if (textLeft != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GuiGetTextWidth(textLeft); + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SLIDER, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + } + + if (textRight != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GuiGetTextWidth(textRight); + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(SLIDER, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + } + //-------------------------------------------------------------------- + + return result; +} + +// Slider Bar control extended, returns selected value +int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) +{ + int result = RESULT_NONE; + int preSliderWidth = GuiGetStyle(SLIDER, SLIDER_WIDTH); + GuiSetStyle(SLIDER, SLIDER_WIDTH, 0); + result = GuiSlider(bounds, textLeft, textRight, value, minValue, maxValue); + GuiSetStyle(SLIDER, SLIDER_WIDTH, preSliderWidth); + + return result; +} + +// Progress Bar control extended, shows current progress value +int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + float temp = (maxValue - minValue)/2.0f; + if (value == NULL) value = &temp; + float prevValue = *value; + + // Progress bar + Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), + bounds.y + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) + GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING), 0, + bounds.height - GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - 2*GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING) -1 }; + + // Update control + //-------------------------------------------------------------------- + if (*value > maxValue) *value = maxValue; + + // WARNING: Working with floats could lead to rounding issues + if ((state != STATE_DISABLED)) progress.width = ((float)*value/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)); + + if (prevValue != *value) result = RESULT_CHANGED; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state == STATE_DISABLED) + { + GuiDrawRectangle(bounds, GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), GetColor(GuiGetStyle(PROGRESSBAR, BORDER + (state*3))), BLANK); + } + else + { + if (*value > minValue) + { + // Draw progress bar with colored border, more visual + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height - 2 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); + } + else GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height+GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)-1 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); + + if (*value >= maxValue) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height+GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)-1}, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); + else + { + // Draw borders not yet reached by value + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y, bounds.width - (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y + bounds.height - 1, bounds.width - (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height+GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)-1 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); + } + + // Draw slider internal progress bar (depends on state) + if (GuiGetStyle(PROGRESSBAR, PROGRESS_SIDE) == 0) // Left-->Right + { + GuiDrawRectangle(progress, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BASE_COLOR_PRESSED))); + } + else // Right-->Left + { + progress.x = bounds.x + bounds.width - progress.width - GuiGetStyle(PROGRESSBAR, BORDER_WIDTH); + GuiDrawRectangle(progress, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BASE_COLOR_PRESSED))); + } + } + + // Draw left/right text if provided + if (textLeft != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GuiGetTextWidth(textLeft); + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x - textBounds.width - GuiGetStyle(PROGRESSBAR, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + } + + if (textRight != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GuiGetTextWidth(textRight); + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(PROGRESSBAR, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + } + //-------------------------------------------------------------------- + + return result; +} + +// Status Bar control +int GuiStatusBar(Rectangle bounds, const char *text) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check checkbox state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + //if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + //else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(STATUSBAR, BORDER_WIDTH), GetColor(GuiGetStyle(STATUSBAR, BORDER + (state*3))), GetColor(GuiGetStyle(STATUSBAR, BASE + (state*3)))); + GuiDrawText(text, GetTextBounds(STATUSBAR, bounds), GuiGetStyle(STATUSBAR, TEXT_ALIGNMENT), GetColor(GuiGetStyle(STATUSBAR, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + +// Dummy rectangle control, intended for placeholding +int GuiDummyRec(Rectangle bounds, const char *text) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check button state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state != STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED))); + GuiDrawText(text, GetTextBounds(DEFAULT, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(BUTTON, (state != STATE_DISABLED)? TEXT_COLOR_NORMAL : TEXT_COLOR_DISABLED))); + //------------------------------------------------------------------ + + return result; +} + +// List View control +int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active) +{ + int result = RESULT_NONE; + int itemCount = 0; + char **items = NULL; + + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount); + + result = GuiListViewEx(bounds, items, itemCount, scrollIndex, active, NULL); + + return result; +} + +// List View control using text entries list and returning focus entry +int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + int itemFocused = (focus == NULL)? -1 : *focus; + int itemSelected = (active == NULL)? -1 : *active; + int prevActive = (active == NULL)? 0 : *active; + + // Check if scroll bar is needed + bool useScrollBar = false; + if ((GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING))*count > bounds.height) useScrollBar = true; + + // Define base item rectangle [0] + Rectangle itemBounds = { 0 }; + itemBounds.x = bounds.x + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING); + itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); + itemBounds.width = bounds.width - 2*GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) - GuiGetStyle(DEFAULT, BORDER_WIDTH); + itemBounds.height = (float)GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT); + if (useScrollBar) itemBounds.width -= GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH); + + // Get items on the list + int visibleItems = (int)bounds.height/(GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING)); + if (visibleItems > count) visibleItems = count; + + int startIndex = (scrollIndex == NULL)? 0 : *scrollIndex; + if ((startIndex < 0) || (startIndex > (count - visibleItems))) startIndex = 0; + int endIndex = startIndex + visibleItems; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check mouse inside list view + if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + + // Check focused and selected item + for (int i = 0; i < visibleItems; i++) + { + if (CheckCollisionPointRec(mousePoint, itemBounds)) + { + itemFocused = startIndex + i; + if (GUI_BUTTON_PRESSED) + { + if (itemSelected == (startIndex + i)) itemSelected = -1; + else itemSelected = startIndex + i; + } + break; + } + + // Update item rectangle y position for next item + itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING)); + } + + if (useScrollBar) + { + float scrollDelta = GUI_SCROLL_DELTA; + startIndex -= (int)scrollDelta; + + if (startIndex < 0) startIndex = 0; + else if (startIndex > (count - visibleItems)) startIndex = count - visibleItems; + + endIndex = startIndex + visibleItems; + if (endIndex > count) endIndex = count; + } + } + else itemFocused = -1; + + // Reset item rectangle y to [0] + itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background + + // Draw visible items + for (int i = 0; ((i < visibleItems) && (text != NULL)); i++) + { + if (GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_NORMAL)) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_NORMAL)), BLANK); + + if (state == STATE_DISABLED) + { + if ((startIndex + i) == itemSelected) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED))); + + GuiDrawText(text[startIndex + i], GetTextBounds(LISTVIEW, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED))); + } + else + { + if (((startIndex + i) == itemSelected) && (active != NULL)) + { + // Draw item selected + GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED))); + GuiDrawText(text[startIndex + i], GetTextBounds(LISTVIEW, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED))); + } + else if (((startIndex + i) == itemFocused)) // && (focus != NULL)) // NOTE: Items focused, despite not returned + { + // Draw item focused + GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED))); + GuiDrawText(text[startIndex + i], GetTextBounds(LISTVIEW, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED))); + } + else + { + // Draw item normal (no rectangle) + GuiDrawText(text[startIndex + i], GetTextBounds(LISTVIEW, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL))); + } + } + + // Update item rectangle y position for next item + itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING)); + } + + if (useScrollBar) + { + Rectangle scrollBarBounds = { + bounds.x + bounds.width - GuiGetStyle(LISTVIEW, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), + bounds.y + GuiGetStyle(LISTVIEW, BORDER_WIDTH), (float)GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), + bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) + }; + + // Calculate percentage of visible items and apply same percentage to scrollbar + float percentVisible = (float)(endIndex - startIndex)/count; + float sliderSize = bounds.height*percentVisible; + + int prevSliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); // Save default slider size + int prevScrollSpeed = GuiGetStyle(SCROLLBAR, SCROLL_SPEED); // Save default scroll speed + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)sliderSize); // Change slider size + GuiSetStyle(SCROLLBAR, SCROLL_SPEED, count - visibleItems); // Change scroll speed + + startIndex = GuiScrollBar(scrollBarBounds, startIndex, 0, count - visibleItems); + + GuiSetStyle(SCROLLBAR, SCROLL_SPEED, prevScrollSpeed); // Reset scroll speed to default + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, prevSliderSize); // Reset slider size to default + } + //-------------------------------------------------------------------- + + if (active != NULL) *active = itemSelected; + if (focus != NULL) *focus = itemFocused; + if (scrollIndex != NULL) *scrollIndex = startIndex; + + if (prevActive != *active) result = RESULT_CHANGED; + + return result; +} + +// Tab Bar control +int GuiTabBar(Rectangle bounds, const char *text, int *hscroll, int *active) +{ + int result = RESULT_NONE; + int itemCount = 0; + char **items = NULL; + + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount); + + result = GuiTabBarEx(bounds, items, itemCount, hscroll, active, NULL); + + return result; +} + +// Tab Bar control, using text entries list and returning focus entry +// NOTE: In case of tab close result, consider focused tab +// TODO: Reeplace GuiToggle() usage for custom implementation for the TABS +int GuiTabBarEx(Rectangle bounds, char **text, int count, int *hscroll, int *active, int *focus) +{ + int result = RESULT_NONE; + //GuiState state = guiState; + + int tabItemsWidth = GuiGetStyle(TABBAR, TAB_ITEMS_WIDTH); + Rectangle tabBounds = { bounds.x, bounds.y, (float)tabItemsWidth, bounds.height }; + + if (*active < 0) *active = 0; + else if (*active > count - 1) *active = count - 1; + + int prevActive = (active == NULL)? 0 : *active; + + int offsetX = 0; // Required in case tabs go out of screen + offsetX = (*active*tabItemsWidth) - GetScreenWidth(); + if (offsetX < 0) offsetX = 0; + + bool toggle = false; // Required for individual toggles + + // Draw control + //-------------------------------------------------------------------- + //if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) // TODO: Support disabled + + for (int i = 0; i < count; i++) + { + tabBounds.x = bounds.x + (tabItemsWidth + 4)*i + offsetX; + + if (tabBounds.x < GetScreenWidth()) + { + // Draw tabs as toggle controls + int textAlignment = GuiGetStyle(TOGGLE, TEXT_ALIGNMENT); + int textPadding = GuiGetStyle(TOGGLE, TEXT_PADDING); + GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(TOGGLE, TEXT_PADDING, 8); + + if (i == (*active)) + { + toggle = true; + GuiToggle(tabBounds, text[i], &toggle); + } + else + { + toggle = false; + GuiToggle(tabBounds, text[i], &toggle); + if (toggle) *active = i; + } + + // Close tab with middle mouse button pressed + if (CheckCollisionPointRec(GUI_POINTER_POSITION, tabBounds) && GUI_BUTTON_PRESSED_MID) result = RESULT_TAB_CLOSE; + + GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding); + GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment); + + if (GuiGetStyle(TABBAR, TAB_CLOSE_BUTTON)) + { + // Draw tab close button + // NOTE: Only draw close button for current tab: if (CheckCollisionPointRec(mousePosition, tabBounds)) + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 1); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); +#if defined(RAYGUI_NO_ICONS) + if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, "x")) result = RESULT_TAB_CLOSE; +#else + if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, + GuiIconText(ICON_CROSS_SMALL, NULL))) result = RESULT_TAB_CLOSE; +#endif + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); + } + } + } + + // Draw tab-bar bottom line + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, 1 }, 0, BLANK, GetColor(GuiGetStyle(TABBAR, BORDER_COLOR_NORMAL))); + //-------------------------------------------------------------------- + + // NOTE: In case of tab close result, consider focused tab + if ((result != RESULT_TAB_CLOSE) && (prevActive != *active)) result = RESULT_CHANGED; + + return result; +} + +// Color Panel control +int GuiColorPanel(Rectangle bounds, const char *text, Color *color) +{ + int result = RESULT_NONE; + + Vector3 vcolor = { (float)color->r/255.0f, (float)color->g/255.0f, (float)color->b/255.0f }; + Vector3 hsv = ConvertRGBtoHSV(vcolor); + Vector3 prevHsv = hsv; // NOTE: Workaround to see if GuiColorPanelHSV() modifies the hsv + + result = GuiColorPanelHSV(bounds, text, &hsv); + + // Check if the hsv was changed, only then change the color + // This is required, because the Color->HSV->Color conversion has precision errors + // Thus the assignment from HSV to Color should only be made, if the HSV has a new user-entered value + // Otherwise GuiColorPanel would often modify it's color without user input + if ((hsv.x != prevHsv.x) || (hsv.y != prevHsv.y) || (hsv.z != prevHsv.z)) + { + Vector3 rgb = ConvertHSVtoRGB(hsv); + *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x), (unsigned char)(255.0f*rgb.y), (unsigned char)(255.0f*rgb.z), color->a }; + } + + return result; +} + +// Color Bar Alpha control +// NOTE: Returns alpha value normalized [0..1] +int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) +{ + #if !defined(RAYGUI_COLORBARALPHA_CHECKED_SIZE) + #define RAYGUI_COLORBARALPHA_CHECKED_SIZE 10 + #endif + + int result = RESULT_NONE; + GuiState state = guiState; + + float prevAlpha = *alpha; + Rectangle selector = { (float)bounds.x + (*alpha)*bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, + (float)bounds.y - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), + (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT), + (float)bounds.height + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2 }; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (GUI_BUTTON_DOWN) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + state = STATE_PRESSED; + + *alpha = (mousePoint.x - bounds.x)/bounds.width; + if (*alpha <= 0.0f) *alpha = 0.0f; + if (*alpha >= 1.0f) *alpha = 1.0f; + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) + { + if (GUI_BUTTON_DOWN) + { + state = STATE_PRESSED; + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + + *alpha = (mousePoint.x - bounds.x)/bounds.width; + if (*alpha <= 0.0f) *alpha = 0.0f; + if (*alpha >= 1.0f) *alpha = 1.0f; + //selector.x = bounds.x + (int)(((alpha - 0)/(100 - 0))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))) - selector.width/2; + } + else state = STATE_FOCUSED; + } + } + + if (prevAlpha != *alpha) result = RESULT_CHANGED; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + // Draw alpha bar: checked background + if (state != STATE_DISABLED) + { + int checksX = (int)bounds.width/RAYGUI_COLORBARALPHA_CHECKED_SIZE; + int checksY = (int)bounds.height/RAYGUI_COLORBARALPHA_CHECKED_SIZE; + + for (int x = 0; x < checksX; x++) + { + for (int y = 0; y < checksY; y++) + { + Rectangle check = { bounds.x + x*RAYGUI_COLORBARALPHA_CHECKED_SIZE, bounds.y + y*RAYGUI_COLORBARALPHA_CHECKED_SIZE, RAYGUI_COLORBARALPHA_CHECKED_SIZE, RAYGUI_COLORBARALPHA_CHECKED_SIZE }; + GuiDrawRectangle(check, 0, BLANK, ((x + y)%2)? Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.4f) : Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.4f)); + } + } + + DrawRectangleGradientEx(bounds, RAYGUI_CLITERAL(Color){ 255, 255, 255, 0 }, RAYGUI_CLITERAL(Color){ 255, 255, 255, 0 }, Fade(RAYGUI_CLITERAL(Color){ 0, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 0, 255 }, guiAlpha)); + } + else DrawRectangleGradientEx(bounds, Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha)); + + GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); + + // Draw alpha bar: selector + GuiDrawRectangle(selector, 0, BLANK, GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3))); + //-------------------------------------------------------------------- + + return result; +} + +// Color Bar Hue control +// Returns hue value normalized [0..1] +// NOTE: Other similar bars (for reference): +// Color GuiColorBarSat() [WHITE->color] +// Color GuiColorBarValue() [BLACK->color], HSV/HSL +// float GuiColorBarLuminance() [BLACK->WHITE] +int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + float prevHue = *hue; + Rectangle selector = { (float)bounds.x - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)bounds.y + (*hue)/360.0f*bounds.height - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2, (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT) }; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (GUI_BUTTON_DOWN) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + state = STATE_PRESSED; + + *hue = (mousePoint.y - bounds.y)*360/bounds.height; + if (*hue <= 0.0f) *hue = 0.0f; + if (*hue >= 359.0f) *hue = 359.0f; + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) + { + if (GUI_BUTTON_DOWN) + { + state = STATE_PRESSED; + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + + *hue = (mousePoint.y - bounds.y)*360/bounds.height; + if (*hue <= 0.0f) *hue = 0.0f; + if (*hue >= 359.0f) *hue = 359.0f; + + } + else state = STATE_FOCUSED; + + /*if (GUI_KEY_DOWN(KEY_UP)) + { + hue -= 2.0f; + if (hue <= 0.0f) hue = 0.0f; + } + else if (GUI_KEY_DOWN(KEY_DOWN)) + { + hue += 2.0f; + if (hue >= 360.0f) hue = 360.0f; + }*/ + } + } + + if (prevHue != *hue) result = RESULT_CHANGED; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state != STATE_DISABLED) + { + // Draw hue bar:color bars + // NOTE: Using DrawRectangleGradientEx(bounds, color1, color2, color2, color1); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 1*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 2*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 3*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 4*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 5*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha)); + } + else + { + DrawRectangleGradientEx(bounds, + Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), + Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha)); + } + + GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); + + // Draw hue bar: selector + GuiDrawRectangle(selector, 0, BLANK, GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3))); + //-------------------------------------------------------------------- + + return result; +} + +// Color Picker control +// NOTE: It's divided in multiple controls: +// Color GuiColorPanel(Rectangle bounds, Color color) +// float GuiColorBarAlpha(Rectangle bounds, float alpha) +// float GuiColorBarHue(Rectangle bounds, float value) +// NOTE: bounds define GuiColorPanel() size +// NOTE: this picker converts RGB to HSV, which can cause the Hue control to jump. If you have this problem, consider using the HSV variant instead +int GuiColorPicker(Rectangle bounds, const char *text, Color *color) +{ + int result = RESULT_NONE; + + Color temp = { 200, 0, 0, 255 }; + if (color == NULL) color = &temp; + + result = GuiColorPanel(bounds, NULL, color); + + Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; + //Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) }; + + // NOTE: this conversion can cause low hue-resolution, if the r, g and b value are very similar, which causes the hue bar to shift around when only the GuiColorPanel is used + Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ (*color).r/255.0f, (*color).g/255.0f, (*color).b/255.0f }); + + if (result != RESULT_CHANGED) result = GuiColorBarHue(boundsHue, NULL, &hsv.x); + + //color.a = (unsigned char)(GuiColorBarAlpha(boundsAlpha, (float)color.a/255.0f)*255.0f); + Vector3 rgb = ConvertHSVtoRGB(hsv); + + *color = RAYGUI_CLITERAL(Color){ (unsigned char)roundf(rgb.x*255.0f), (unsigned char)roundf(rgb.y*255.0f), (unsigned char)roundf(rgb.z*255.0f), (*color).a }; + + return result; +} + +// Color Picker control that avoids conversion to RGB and back to HSV on each call, thus avoiding jittering +// The user can call ConvertHSVtoRGB() to convert *colorHsv value to RGB +// NOTE: It's divided in multiple controls: +// int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) +// int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) +// float GuiColorBarHue(Rectangle bounds, float value) +// NOTE: bounds define GuiColorPanelHSV() size +int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) +{ + int result = RESULT_NONE; + + Vector3 tempHsv = { 0 }; + + if (colorHsv == NULL) + { + const Vector3 tempColor = { 200.0f/255.0f, 0.0f, 0.0f }; + tempHsv = ConvertRGBtoHSV(tempColor); + colorHsv = &tempHsv; + } + + result = GuiColorPanelHSV(bounds, NULL, colorHsv); + + Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; + + if (result == RESULT_NONE) result = GuiColorBarHue(boundsHue, NULL, &colorHsv->x); + + return result; +} + +// Color Panel control - HSV variant +int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + Vector3 prevColorHsv = *colorHsv; + Vector2 pickerSelector = { 0 }; + const Color colWhite = { 255, 255, 255, 255 }; + const Color colBlack = { 0, 0, 0, 255 }; + + pickerSelector.x = bounds.x + (float)colorHsv->y*bounds.width; // HSV: Saturation + pickerSelector.y = bounds.y + (1.0f - (float)colorHsv->z)*bounds.height; // HSV: Value + + Vector3 maxHue = { colorHsv->x, 1.0f, 1.0f }; + Vector3 rgbHue = ConvertHSVtoRGB(maxHue); + Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x), (unsigned char)(255.0f*rgbHue.y), (unsigned char)(255.0f*rgbHue.z), 255 }; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (GUI_BUTTON_DOWN) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + pickerSelector = mousePoint; + + if (pickerSelector.x < bounds.x) pickerSelector.x = bounds.x; + if (pickerSelector.x > bounds.x + bounds.width) pickerSelector.x = bounds.x + bounds.width; + if (pickerSelector.y < bounds.y) pickerSelector.y = bounds.y; + if (pickerSelector.y > bounds.y + bounds.height) pickerSelector.y = bounds.y + bounds.height; + + // Calculate color from picker + Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y }; + + colorPick.x /= (float)bounds.width; // Get normalized value on x + colorPick.y /= (float)bounds.height; // Get normalized value on y + + colorHsv->y = colorPick.x; + colorHsv->z = 1.0f - colorPick.y; + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) + { + state = STATE_PRESSED; + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; + pickerSelector = mousePoint; + + // Calculate color from picker + Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y }; + + colorPick.x /= (float)bounds.width; // Get normalized value on x + colorPick.y /= (float)bounds.height; // Get normalized value on y + + colorHsv->y = colorPick.x; + colorHsv->z = 1.0f - colorPick.y; + } + else state = STATE_FOCUSED; + } + } + + if ((prevColorHsv.x != colorHsv->x) || + (prevColorHsv.y != colorHsv->y) || + (prevColorHsv.z != colorHsv->z)) result = RESULT_CHANGED; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state != STATE_DISABLED) + { + DrawRectangleGradientEx(bounds, Fade(colWhite, guiAlpha), Fade(colWhite, guiAlpha), Fade(maxHueCol, guiAlpha), Fade(maxHueCol, guiAlpha)); + DrawRectangleGradientEx(bounds, Fade(colBlack, 0), Fade(colBlack, guiAlpha), Fade(colBlack, guiAlpha), Fade(colBlack, 0)); + + // Draw color picker: selector + Rectangle selector = { pickerSelector.x - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, pickerSelector.y - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE), (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE) }; + GuiDrawRectangle(selector, 0, BLANK, colWhite); + } + else + { + DrawRectangleGradientEx(bounds, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.6f), guiAlpha)); + } + + GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); + //-------------------------------------------------------------------- + + return result; +} + +// Message Box control +// NOTE: Button pressed is returned through btnActive parameter, 0 for window close button +int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *btnText, int *btnActive) +{ + #if !defined(RAYGUI_MESSAGEBOX_BUTTON_HEIGHT) + #define RAYGUI_MESSAGEBOX_BUTTON_HEIGHT 24 + #endif + #if !defined(RAYGUI_MESSAGEBOX_BUTTON_PADDING) + #define RAYGUI_MESSAGEBOX_BUTTON_PADDING 12 + #endif + + int result = RESULT_NONE; + + int buttonCount = 0; + char **btnTextList = GuiTextSplit(btnText, ';', &buttonCount); + Rectangle buttonBounds = { 0 }; + buttonBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING; + buttonBounds.y = bounds.y + bounds.height - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT - RAYGUI_MESSAGEBOX_BUTTON_PADDING; + buttonBounds.width = (bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount; + buttonBounds.height = RAYGUI_MESSAGEBOX_BUTTON_HEIGHT; + + //int textWidth = GuiGetTextWidth(message) + 2; + + Rectangle textBounds = { 0 }; + textBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING; + textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + RAYGUI_MESSAGEBOX_BUTTON_PADDING; + textBounds.width = bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*2; + textBounds.height = bounds.height - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 3*RAYGUI_MESSAGEBOX_BUTTON_PADDING - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT; + + // Draw control + //-------------------------------------------------------------------- + if (GuiWindowBox(bounds, title) == RESULT_PRESSED) + { + *btnActive = 0; + result = RESULT_PRESSED; + } + + int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + GuiLabel(textBounds, message); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment); + + prevTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + + for (int i = 0; i < buttonCount; i++) + { + if (GuiButton(buttonBounds, btnTextList[i])) + { + *btnActive = i + 1; + result = RESULT_PRESSED; + } + buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING); + } + + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevTextAlignment); + //-------------------------------------------------------------------- + + return result; +} + +// Text Input Box control +// NOTE: Button pressed is returned through btnActive parameter, 0 for window close button +int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, char *text, int textSize, const char *btnText, int *btnActive, bool *secretViewActive) +{ + #if !defined(RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT) + #define RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT 24 + #endif + #if !defined(RAYGUI_TEXTINPUTBOX_BUTTON_PADDING) + #define RAYGUI_TEXTINPUTBOX_BUTTON_PADDING 12 + #endif + #if !defined(RAYGUI_TEXTINPUTBOX_HEIGHT) + #define RAYGUI_TEXTINPUTBOX_HEIGHT 26 + #endif + + int result = RESULT_NONE; + + // Used to enable text edit mode + // WARNING: No more than one GuiTextInputBox() should be open at the same time + static bool textEditMode = false; + + int buttonCount = 0; + char **btnTextList = GuiTextSplit(btnText, ';', &buttonCount); + Rectangle buttonBounds = { 0 }; + buttonBounds.x = bounds.x + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; + buttonBounds.y = bounds.y + bounds.height - RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; + buttonBounds.width = (bounds.width - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount; + buttonBounds.height = RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT; + + int messageInputHeight = (int)bounds.height - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT - 2*RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; + + Rectangle textBounds = { 0 }; + if (message != NULL) + { + int textSize = GuiGetTextWidth(message) + 2; + + textBounds.x = bounds.x + bounds.width/2 - textSize/2; + textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + messageInputHeight/4 - (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + textBounds.width = (float)textSize; + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + } + + Rectangle textBoxBounds = { 0 }; + textBoxBounds.x = bounds.x + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; + textBoxBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - RAYGUI_TEXTINPUTBOX_HEIGHT/2; + if (message == NULL) textBoxBounds.y = bounds.y + 24 + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; + else textBoxBounds.y += (messageInputHeight/2 + messageInputHeight/4); + textBoxBounds.width = bounds.width - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING*2; + textBoxBounds.height = RAYGUI_TEXTINPUTBOX_HEIGHT; + + // Draw control + //-------------------------------------------------------------------- + if (GuiWindowBox(bounds, title) == RESULT_PRESSED) + { + *btnActive = 0; + result = RESULT_PRESSED; + } + + // Draw message if available + if (message != NULL) + { + int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + GuiLabel(textBounds, message); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment); + } + + int prevTextBoxAlignment = GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT); + GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + + if (secretViewActive != NULL) + { + static char stars[] = "****************"; + if (GuiTextBox(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x, textBoxBounds.y, textBoxBounds.width - 4 - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.height }, + ((*secretViewActive == 1) || textEditMode)? text : stars, textSize, textEditMode) == RESULT_PRESSED) textEditMode = !textEditMode; + +#if defined(RAYGUI_NO_ICONS) + GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, + (*secretViewActive == 1)? "O" : "*", secretViewActive); +#else + GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, + (*secretViewActive == 1)? GuiIconText(ICON_EYE_ON, NULL) : GuiIconText(ICON_EYE_OFF, NULL), secretViewActive); +#endif + } + else + { + if (GuiTextBox(textBoxBounds, text, textSize, textEditMode) == RESULT_PRESSED) + textEditMode = !textEditMode; + } + + GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, prevTextBoxAlignment); + + int prevBtnTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + + for (int i = 0; i < buttonCount; i++) + { + if (GuiButton(buttonBounds, btnTextList[i])) + { + *btnActive = i + 1; + result = RESULT_PRESSED; + } + + buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING); + } + + if (result == RESULT_PRESSED) textEditMode = false; + + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevBtnTextAlignment); + //-------------------------------------------------------------------- + + return result; +} + +// Grid control +// NOTE: Returns grid mouse-hover selected cell +// About drawing lines at subpixel spacing, simple put, not easy solution: +// REF: https://stackoverflow.com/questions/4435450/2d-opengl-drawing-lines-that-dont-exactly-fit-pixel-raster +int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vector2 *mouseCell) +{ + // Grid lines alpha amount + #if !defined(RAYGUI_GRID_ALPHA) + #define RAYGUI_GRID_ALPHA 0.15f + #endif + + int result = RESULT_NONE; + GuiState state = guiState; + + Vector2 mousePoint = GUI_POINTER_POSITION; + Vector2 currentMouseCell = { -1, -1 }; + + float spaceWidth = spacing/(float)subdivs; + int linesV = (int)(bounds.width/spaceWidth) + 1; + int linesH = (int)(bounds.height/spaceWidth) + 1; + + int color = GuiGetStyle(DEFAULT, LINE_COLOR); + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + if (CheckCollisionPointRec(mousePoint, bounds)) + { + // NOTE: Cell values must be the upper left of the cell the mouse is in + currentMouseCell.x = floorf((mousePoint.x - bounds.x)/spacing); + currentMouseCell.y = floorf((mousePoint.y - bounds.y)/spacing); + + result = RESULT_PRESSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state == STATE_DISABLED) color = GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED); + + if (subdivs > 0) + { + // Draw vertical grid lines + for (int i = 0; i < linesV; i++) + { + Rectangle lineV = { bounds.x + spacing*i/subdivs, bounds.y, 1, bounds.height + 1 }; + GuiDrawRectangle(lineV, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(color), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(color), RAYGUI_GRID_ALPHA)); + } + + // Draw horizontal grid lines + for (int i = 0; i < linesH; i++) + { + Rectangle lineH = { bounds.x, bounds.y + spacing*i/subdivs, bounds.width + 1, 1 }; + GuiDrawRectangle(lineH, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(color), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(color), RAYGUI_GRID_ALPHA)); + } + } + + if (mouseCell != NULL) *mouseCell = currentMouseCell; + + return result; +} + +//---------------------------------------------------------------------------------- +// Tooltip management functions +// NOTE: Tooltips requires some global variables: tooltipPtr +//---------------------------------------------------------------------------------- +// Enable gui tooltips (global state) +void GuiEnableTooltip(void) { guiTooltip = true; } + +// Disable gui tooltips (global state) +void GuiDisableTooltip(void) { guiTooltip = false; } + +// Set tooltip string +void GuiSetTooltip(const char *tooltip) { guiTooltipPtr = tooltip; } + +//---------------------------------------------------------------------------------- +// Styles loading functions +//---------------------------------------------------------------------------------- + +// Load raygui style file (.rgs) +// NOTE: By default a binary file is expected, that file could contain a custom font, +// in that case, custom font image atlas is GRAY+ALPHA and pixel data can be compressed (DEFLATE) +void GuiLoadStyle(const char *fileName) +{ + #define MAX_LINE_BUFFER_SIZE 256 + + bool tryBinary = false; + if (!guiStyleLoaded) GuiLoadStyleDefault(); + + // Try reading the files as text file first + FILE *rgsFile = fopen(fileName, "rt"); + + if (rgsFile != NULL) + { + char buffer[MAX_LINE_BUFFER_SIZE] = { 0 }; + fgets(buffer, MAX_LINE_BUFFER_SIZE, rgsFile); + + if (buffer[0] == '#') + { + int controlId = 0; + int propertyId = 0; + unsigned int propertyValue = 0; + unsigned int version = 0; + + while (!feof(rgsFile)) + { + switch (buffer[0]) + { + case 'v': + { + sscanf(buffer, "v %d", &version); + } + case 'p': + { + // Style property: p + + sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue); + GuiSetStyle(controlId, propertyId, (int)propertyValue); + + } break; + case 'f': + { + // Style font: f + + int fontSize = 0; + char charmapFileName[32] = { 0 }; + char fontFileName[32] = { 0 }; + + if (version >= 600) sscanf(buffer, "f %d %31s %31[^\r\n]s", &fontSize, fontFileName, charmapFileName); + else sscanf(buffer, "f %d %31s %31[^\r\n]s", &fontSize, charmapFileName, fontFileName); + + // GLOBAL: Copy font file name into guiFontName + snprintf(guiFontName, 32, "%s", fontFileName); + + Font font = { 0 }; + int *codepoints = NULL; + int codepointCount = 0; + + if (charmapFileName[0] != '0') + { + // Load text data from file + // NOTE: Expected an UTF-8 array of codepoints, no separation + char *textData = LoadFileText(TextFormat("%s/%s", GetDirectoryPath(fileName), charmapFileName)); + codepoints = LoadCodepoints(textData, &codepointCount); + UnloadFileText(textData); + } + + if (fontFileName[0] != '\0') + { + // In case a font is already loaded and it is not default internal font, unload it + if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture); + + if (codepointCount > 0) font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, codepoints, codepointCount); + else font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, NULL, 0); // Default to 95 standard codepoints + } + + // If font texture not properly loaded, revert to default font and size/spacing + if (font.texture.id == 0) + { + font = GetFontDefault(); + GuiSetStyle(DEFAULT, TEXT_SIZE, 10); + GuiSetStyle(DEFAULT, TEXT_SPACING, 1); + } + + UnloadCodepoints(codepoints); + + if ((font.texture.id > 0) && (font.glyphCount > 0)) GuiSetFont(font); + + } break; + default: break; + } + + fgets(buffer, MAX_LINE_BUFFER_SIZE, rgsFile); + } + } + else tryBinary = true; + + fclose(rgsFile); + } + + if (tryBinary) + { + rgsFile = fopen(fileName, "rb"); + + if (rgsFile != NULL) + { + fseek(rgsFile, 0, SEEK_END); + int fileDataSize = ftell(rgsFile); + fseek(rgsFile, 0, SEEK_SET); + + if (fileDataSize > 0) + { + unsigned char *fileData = (unsigned char *)RAYGUI_CALLOC(fileDataSize, sizeof(unsigned char)); + if (fileData != NULL) + { + fread(fileData, sizeof(unsigned char), fileDataSize, rgsFile); + + GuiLoadStyleFromMemory(fileData, fileDataSize); + + RAYGUI_FREE(fileData); + } + } + + fclose(rgsFile); + } + } +} + +// Load style from memory +// WARNING: Binary files only +void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize) +{ + // Style File Structure (.rgs) + // ------------------------------------------------------ + // Offset | Size | Type | Description + // ------------------------------------------------------ + // 0 | 4 | char | Signature: "rGS " + // 4 | 2 | short | Version: 200, 400, 600 + // 6 | 2 | short | reserved + // 8 | 4 | int | Num properties (only changed ones from default style) + + // Properties Data (8 bytes per property) + // WARNING: Only properties required that differ from default (light) internal style + // foreach (property) + // { + // 8+8*i | 2 | short | ControlId + // 8+8*i | 2 | short | PropertyId + // 8+8*i | 4 | int | PropertyValue + // } + + // Custom Font Data : Parameters (64 bytes) + // ... | 4 | int | Font data size (0 - no font, no more fields added!) + // ... | 32 | char | Font filename (with extension) - VERSION: >=600 + // ... | 4 | int | Font base size + // ... | 4 | int | Font glyph count [glyphCount] + // ... | 4 | int | Font type (0-NORMAL, 1-SDF) + // ... | 16 | Rectangle | Font white rectangle + + // Custom Font Data : Image (20 bytes + imData) + // NOTE: Font image atlas is always converted to GRAY+ALPHA + // and atlas image data can be compressed (DEFLATE) + // ... | 4 | int | Image data size (uncompressed) + // ... | 4 | int | Image data size (compressed) + // ... | 4 | int | Image width + // ... | 4 | int | Image height + // ... | 4 | int | Image format: GRAY+ALPHA (expected) + // ... | imSize | byte | Image data (comp or uncomp) + + // Custom Font Data : Recs (32 bytes*glyphCount) + // NOTE: Font recs data can be compressed (DEFLATE) + // ... | 4 | int | Recs data compressed size (0 - not compressed, 1-compressed) - VERSION: >=400 + // + // if (compRecsSize == 0) + // { + // NOTE: Uncompressed size can be calculated: (glyphCount*16 byte) + // foreach (glyph) + // { + // ... | 16 | Rectangle | Glyph rectangle (in image) + // } + // } + // else + // { + // ... | compRecsSize | byte | Rectangles data + // } + // + + // Custom Font Data : Glyph Info (32 bytes*glyphCount) + // NOTE: Font glyphs info data can be compressed (DEFLATE) + // ... | 4 | int | Glyphs data compressed size (0 - not compressed) - VERSION: >=400 + // + // if (compGlyphsSize == 0) + // { + // NOTE: Uncompressed size can be calculated: (glyphCount*16 byte) + // foreach (glyph) + // { + // ... | 4 | int | Glyph value + // ... | 4 | int | Glyph offset X + // ... | 4 | int | Glyph offset Y + // ... | 4 | int | Glyph advance X + // } + // } + // else + // { + // ... | compGlyphsSize | byte | Glyphs data + // } + // ------------------------------------------------------ + + unsigned char *fileDataPtr = (unsigned char *)fileData; + + char signature[5] = { 0 }; + short version = 0; + short reserved = 0; + int propertyCount = 0; + + memcpy(signature, fileDataPtr, 4); + memcpy(&version, fileDataPtr + 4, sizeof(short)); + memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short)); + memcpy(&propertyCount, fileDataPtr + 4 + 2 + 2, sizeof(int)); + fileDataPtr += 12; + + if ((signature[0] == 'r') && + (signature[1] == 'G') && + (signature[2] == 'S') && + (signature[3] == ' ')) + { + short controlId = 0; + short propertyId = 0; + unsigned int propertyValue = 0; + + for (int i = 0; i < propertyCount; i++) + { + memcpy(&controlId, fileDataPtr, sizeof(short)); + memcpy(&propertyId, fileDataPtr + 2, sizeof(short)); + memcpy(&propertyValue, fileDataPtr + 2 + 2, sizeof(unsigned int)); + fileDataPtr += 8; + + if (controlId == 0) // DEFAULT control + { + // If a DEFAULT property is loaded, it is propagated to all controls + // NOTE: All DEFAULT properties should be defined first in the file + GuiSetStyle(0, (int)propertyId, propertyValue); + + if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int j = 1; j < RAYGUI_MAX_CONTROLS; j++) GuiSetStyle(j, (int)propertyId, propertyValue); + } + else GuiSetStyle((int)controlId, (int)propertyId, propertyValue); + } + + // Load custom font if available + // NOTE: Font texture loading requires raylib + int fontDataSize = 0; + memcpy(&fontDataSize, fileDataPtr, sizeof(int)); + fileDataPtr += 4; + + if (fontDataSize > 0) + { + Font font = { 0 }; + int fontType = 0; // 0-Normal, 1-SDF + + // WARNING: Version 600 adds 32 bytes for the font filename (with extension) + if (version >= 600) + { + // GLOBAL: Copy font file name into guiFontName + memcpy(guiFontName, fileDataPtr, 32); + fileDataPtr += 32; + } + else memset(guiFontName, 0, 32); + + memcpy(&font.baseSize, fileDataPtr, sizeof(int)); + memcpy(&font.glyphCount, fileDataPtr + 4, sizeof(int)); + memcpy(&fontType, fileDataPtr + 4 + 4, sizeof(int)); + fileDataPtr += 12; + + // Load font white rectangle + Rectangle fontWhiteRec = { 0 }; + memcpy(&fontWhiteRec, fileDataPtr, sizeof(Rectangle)); + fileDataPtr += 16; + + // Load font image parameters + int fontImageUncompSize = 0; + int fontImageCompSize = 0; + memcpy(&fontImageUncompSize, fileDataPtr, sizeof(int)); + memcpy(&fontImageCompSize, fileDataPtr + 4, sizeof(int)); + fileDataPtr += 8; + + Image imFont = { 0 }; + imFont.mipmaps = 1; + memcpy(&imFont.width, fileDataPtr, sizeof(int)); + memcpy(&imFont.height, fileDataPtr + 4, sizeof(int)); + memcpy(&imFont.format, fileDataPtr + 4 + 4, sizeof(int)); + fileDataPtr += 12; + + if ((fontImageCompSize > 0) && (fontImageCompSize != fontImageUncompSize)) + { + // Compressed font atlas image data (DEFLATE), it requires DecompressData() + int dataUncompSize = 0; + unsigned char *compData = (unsigned char *)RAYGUI_CALLOC(fontImageCompSize, sizeof(unsigned char)); + memcpy(compData, fileDataPtr, fontImageCompSize); + fileDataPtr += fontImageCompSize; + + imFont.data = DecompressData(compData, fontImageCompSize, &dataUncompSize); + + // Security check, dataUncompSize must match the provided fontImageUncompSize + if (dataUncompSize != fontImageUncompSize) RAYGUI_LOG("WARNING: Uncompressed font atlas image data could be corrupted"); + + RAYGUI_FREE(compData); + } + else + { + // Font atlas image data is not compressed + imFont.data = (unsigned char *)RAYGUI_CALLOC(fontImageUncompSize, sizeof(unsigned char)); + memcpy(imFont.data, fileDataPtr, fontImageUncompSize); + fileDataPtr += fontImageUncompSize; + } + + // Load font recs data (glyphs position and size in the image atlas) + int recsDataSize = font.glyphCount*sizeof(Rectangle); + int recsDataCompressedSize = 0; + + // WARNING: Version 400 adds the compression size parameter + if (version >= 400) + { + // RGS files version 400 support compressed recs data + memcpy(&recsDataCompressedSize, fileDataPtr, sizeof(int)); + fileDataPtr += sizeof(int); + } + + if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize)) + { + // Recs data is compressed, uncompress it + unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_CALLOC(recsDataCompressedSize, sizeof(unsigned char)); + + memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize); + fileDataPtr += recsDataCompressedSize; + + int recsDataUncompSize = 0; + font.recs = (Rectangle *)DecompressData(recsDataCompressed, recsDataCompressedSize, &recsDataUncompSize); + + // Security check, data uncompressed size must match the expected original data size + if (recsDataUncompSize != recsDataSize) RAYGUI_LOG("WARNING: Uncompressed font recs data could be corrupted"); + + RAYGUI_FREE(recsDataCompressed); + } + else + { + // Recs data is uncompressed + font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle)); + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.recs[i], fileDataPtr, sizeof(Rectangle)); + fileDataPtr += sizeof(Rectangle); + } + } + + // Load font glyphs info data + int glyphsDataSize = font.glyphCount*16; // 16 bytes data per glyph + int glyphsDataCompressedSize = 0; + + // WARNING: Version 400 adds the compression size parameter + if (version >= 400) + { + // RGS files version 400 support compressed glyphs data + memcpy(&glyphsDataCompressedSize, fileDataPtr, sizeof(int)); + fileDataPtr += sizeof(int); + } + + // Allocate required glyphs space to fill with data + font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo)); + + if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize)) + { + // Glyphs data is compressed, uncompress it + unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_CALLOC(glyphsDataCompressedSize, sizeof(unsigned char)); + + memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize); + fileDataPtr += glyphsDataCompressedSize; + + int glyphsDataUncompSize = 0; + unsigned char *glyphsDataUncomp = DecompressData(glypsDataCompressed, glyphsDataCompressedSize, &glyphsDataUncompSize); + + // Security check, data uncompressed size must match the expected original data size + if (glyphsDataUncompSize != glyphsDataSize) RAYGUI_LOG("WARNING: Uncompressed font glyphs data could be corrupted"); + + unsigned char *glyphsDataUncompPtr = glyphsDataUncomp; + + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.glyphs[i].value, glyphsDataUncompPtr, sizeof(int)); + memcpy(&font.glyphs[i].offsetX, glyphsDataUncompPtr + 4, sizeof(int)); + memcpy(&font.glyphs[i].offsetY, glyphsDataUncompPtr + 8, sizeof(int)); + memcpy(&font.glyphs[i].advanceX, glyphsDataUncompPtr + 12, sizeof(int)); + glyphsDataUncompPtr += 16; + } + + RAYGUI_FREE(glypsDataCompressed); + RAYGUI_FREE(glyphsDataUncomp); + } + else + { + // Glyphs data is uncompressed + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.glyphs[i].value, fileDataPtr, sizeof(int)); + memcpy(&font.glyphs[i].offsetX, fileDataPtr + 4, sizeof(int)); + memcpy(&font.glyphs[i].offsetY, fileDataPtr + 8, sizeof(int)); + memcpy(&font.glyphs[i].advanceX, fileDataPtr + 12, sizeof(int)); + fileDataPtr += 16; + } + } + +#if defined(RAYGUI_FONT_ICONS_BAKING) + // Font atlas image icons baking + Rectangle updatedWhiteRec = { 0 }; + guiIconFontOffsetY = GuiFontIconBaking(&imFont, font, &updatedWhiteRec); + if (guiIconFontOffsetY > 0) fontWhiteRec = updatedWhiteRec; +#endif + +#if !defined(RAYGUI_STANDALONE) + // Load texture from image + if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture); + font.texture = LoadTextureFromImage(imFont); + + // Fallback to default raylib texture if font texture loading fails + if (font.texture.id != 0) + { + // Set font texture source rectangle to be used as white texture to draw shapes + // NOTE: It makes possible to draw shapes and text (full UI) in a single draw call + if ((fontWhiteRec.x > 0) && + (fontWhiteRec.y > 0) && + (fontWhiteRec.width > 0) && + (fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec); + } + else font = GetFontDefault(); + + GuiSetFont(font); +#endif + RAYGUI_FREE(imFont.data); + } + } +} + +// Load style default over global style +void GuiLoadStyleDefault(void) +{ + // Setting this flag first to avoid cyclic function calls + // when calling GuiSetStyle() and GuiGetStyle() + guiStyleLoaded = true; + + // Initialize default LIGHT style property values + // WARNING: Default value are applied to all controls on set but + // they can be overwritten later on for every custom control + GuiSetStyle(DEFAULT, BORDER_COLOR_NORMAL, 0x838383ff); + GuiSetStyle(DEFAULT, BASE_COLOR_NORMAL, 0xc9c9c9ff); + GuiSetStyle(DEFAULT, TEXT_COLOR_NORMAL, 0x686868ff); + GuiSetStyle(DEFAULT, BORDER_COLOR_FOCUSED, 0x5bb2d9ff); + GuiSetStyle(DEFAULT, BASE_COLOR_FOCUSED, 0xc9effeff); + GuiSetStyle(DEFAULT, TEXT_COLOR_FOCUSED, 0x6c9bbcff); + GuiSetStyle(DEFAULT, BORDER_COLOR_PRESSED, 0x0492c7ff); + GuiSetStyle(DEFAULT, BASE_COLOR_PRESSED, 0x97e8ffff); + GuiSetStyle(DEFAULT, TEXT_COLOR_PRESSED, 0x368bafff); + GuiSetStyle(DEFAULT, BORDER_COLOR_DISABLED, 0xb5c1c2ff); + GuiSetStyle(DEFAULT, BASE_COLOR_DISABLED, 0xe6e9e9ff); + GuiSetStyle(DEFAULT, TEXT_COLOR_DISABLED, 0xaeb7b8ff); + GuiSetStyle(DEFAULT, BORDER_WIDTH, 1); + GuiSetStyle(DEFAULT, TEXT_PADDING, 0); + GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + + // Initialize default extended property values + // NOTE: By default, extended property values are initialized to 0 + GuiSetStyle(DEFAULT, TEXT_SIZE, 10); // DEFAULT, shared by all controls + GuiSetStyle(DEFAULT, TEXT_SPACING, 1); // DEFAULT, shared by all controls + GuiSetStyle(DEFAULT, LINE_COLOR, 0x90abb5ff); // DEFAULT specific property + GuiSetStyle(DEFAULT, BACKGROUND_COLOR, 0xf5f5f5ff); // DEFAULT specific property + GuiSetStyle(DEFAULT, TEXT_LINE_SPACING, 12); // DEFAULT, pixels between lines, from bottom of first line to top of second + GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); // DEFAULT, text aligned vertically to middle of text-bounds + + // Initialize control-specific property values + // NOTE: Those properties are in default list but require specific values by control type + GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 2); + GuiSetStyle(SLIDER, TEXT_PADDING, 4); + GuiSetStyle(PROGRESSBAR, TEXT_PADDING, 4); + GuiSetStyle(CHECKBOX, TEXT_PADDING, 4); + GuiSetStyle(CHECKBOX, TEXT_ALIGNMENT, TEXT_ALIGN_RIGHT); + GuiSetStyle(DROPDOWNBOX, TEXT_PADDING, 0); + GuiSetStyle(DROPDOWNBOX, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + GuiSetStyle(TEXTBOX, TEXT_PADDING, 4); + GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(VALUEBOX, TEXT_PADDING, 0); + GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(STATUSBAR, TEXT_PADDING, 8); + GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(TABBAR, TAB_ITEMS_WIDTH, 160); + + // Initialize extended property values + // NOTE: By default, extended property values are initialized to 0 + GuiSetStyle(TOGGLE, GROUP_PADDING, 2); + GuiSetStyle(SLIDER, SLIDER_WIDTH, 16); + GuiSetStyle(SLIDER, SLIDER_PADDING, 1); + GuiSetStyle(PROGRESSBAR, PROGRESS_PADDING, 1); + GuiSetStyle(CHECKBOX, CHECK_PADDING, 1); + GuiSetStyle(COMBOBOX, COMBO_BUTTON_WIDTH, 32); + GuiSetStyle(COMBOBOX, COMBO_BUTTON_SPACING, 2); + GuiSetStyle(DROPDOWNBOX, ARROW_PADDING, 16); + GuiSetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING, 2); + GuiSetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH, 24); + GuiSetStyle(VALUEBOX, SPINNER_BUTTON_SPACING, 2); + GuiSetStyle(SCROLLBAR, BORDER_WIDTH, 0); + GuiSetStyle(SCROLLBAR, ARROWS_VISIBLE, 0); + GuiSetStyle(SCROLLBAR, ARROWS_SIZE, 6); + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING, 0); + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, 16); + GuiSetStyle(SCROLLBAR, SCROLL_PADDING, 0); + GuiSetStyle(SCROLLBAR, SCROLL_SPEED, 12); + GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, 28); + GuiSetStyle(LISTVIEW, LIST_ITEMS_SPACING, 2); + GuiSetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH, 1); + GuiSetStyle(LISTVIEW, SCROLLBAR_WIDTH, 12); + GuiSetStyle(LISTVIEW, SCROLLBAR_SIDE, SCROLLBAR_RIGHT_SIDE); + GuiSetStyle(COLORPICKER, COLOR_SELECTOR_SIZE, 8); + GuiSetStyle(COLORPICKER, HUEBAR_WIDTH, 16); + GuiSetStyle(COLORPICKER, HUEBAR_PADDING, 8); + GuiSetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT, 8); + GuiSetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW, 2); + + if (guiFont.texture.id != GetFontDefault().texture.id) + { + // Unload previous font texture + UnloadTexture(guiFont.texture); + RAYGUI_FREE(guiFont.recs); + RAYGUI_FREE(guiFont.glyphs); + guiFont.recs = NULL; + guiFont.glyphs = NULL; + + // Setup default raylib font + guiFont = GetFontDefault(); + + // NOTE: Default raylib font character 95 is a white square + Rectangle whiteChar = guiFont.recs[95]; + + // NOTE: Setting up a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering + SetShapesTexture(guiFont.texture, RAYGUI_CLITERAL(Rectangle){ whiteChar.x + 1, whiteChar.y + 1, whiteChar.width - 2, whiteChar.height - 2 }); + + // Reset baked icons offset in font + guiIconFontOffsetY = 0; + } +} + +// Get text with icon id prepended +// NOTE: Useful to add icons by name id (enum) instead of +// a number that can change between ricon versions +const char *GuiIconText(int iconId, const char *text) +{ +#if defined(RAYGUI_NO_ICONS) + return NULL; +#else + static char buffer[1024] = { 0 }; + static char iconBuffer[16] = { 0 }; + + if (text != NULL) + { + memset(buffer, 0, 1024); + snprintf(buffer, 1024, "#%03i#", iconId); + + for (int i = 5; i < 1024; i++) + { + buffer[i] = text[i - 5]; + if (text[i - 5] == '\0') break; + } + + return buffer; + } + else + { + snprintf(iconBuffer, 16, "#%03i#", iconId); + + return iconBuffer; + } +#endif +} + +#if !defined(RAYGUI_NO_ICONS) +// Get full icons data pointer +unsigned int *GuiGetIcons(void) { return guiIconsPtr; } + +// Load raygui icons file (.rgi) +// WARNING: guiIconsName[]][] memory should be manually freed! +char **GuiLoadIcons(const char *fileName, bool loadIconsName) +{ + FILE *rgiFile = fopen(fileName, "rb"); + char **guiIconsName = NULL; + + if (rgiFile != NULL) + { + unsigned char *fileData = NULL; + int dataSize = 0; + + fseek(rgiFile, 0, SEEK_END); + int size = (int)ftell(rgiFile); + fseek(rgiFile, 0, SEEK_SET); + + if (size > 0) + { + fileData = (unsigned char *)RL_CALLOC(size, sizeof(unsigned char)); + // WARNING: File can be partially loaded but ignoring it for simplicity + dataSize = (int)fread(fileData, sizeof(unsigned char), size, rgiFile); + + guiIconsName = GuiLoadIconsFromMemory(fileData, dataSize, loadIconsName); + } + + fclose(rgiFile); + } + + return guiIconsName; +} + +// Load icons from memory +// GLOBAL: Updates global variable: guiIconsPtr +char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName) +{ + // Icon File Structure (.rgi) + // ------------------------------------------------------ + // Offset | Size | Type | Description + // ------------------------------------------------------ + // 0 | 4 | char | Signature: "rGI " + // 4 | 2 | short | Version: 100, 500 + // 6 | 2 | short | reserved + + // 8 | 2 | short | Num icons (N) + // 10 | 2 | short | Icons Size (Options: 16, 32, 64) + + // Icons name id (32 bytes per name id) + // foreach (icon) + // { + // 12+32*i | 32 | char | Icon NameId + // } + + // Icons data: One bit per pixel, stored as unsigned int array (depends on icon size) + // Size*Size pixels/32bit per unsigned int = K unsigned int per icon + // foreach (icon) + // { + // ... | K | unsigned int | Icon Data + // } + // ------------------------------------------------------ + + unsigned char *fileDataPtr = (unsigned char *)fileData; + char **guiIconsName = NULL; + + char signature[5] = { 0 }; + short version = 0; + short reserved = 0; + short iconCount = 0; + short iconSize = 0; + + memcpy(signature, fileDataPtr, 4); + memcpy(&version, fileDataPtr + 4, sizeof(short)); + memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short)); + memcpy(&iconCount, fileDataPtr + 4 + 2 + 2, sizeof(short)); + memcpy(&iconSize, fileDataPtr + 4 + 2 + 2 + 2, sizeof(short)); + fileDataPtr += 12; + + if ((signature[0] == 'r') && + (signature[1] == 'G') && + (signature[2] == 'I') && + (signature[3] == ' ')) + { + if (loadIconsName) + { + // NOTE: Always allocating RAYGUI_ICON_MAX_ICONS names slots + guiIconsName = (char **)RAYGUI_CALLOC(RAYGUI_ICON_MAX_ICONS, sizeof(char *)); + for (int i = 0; i < iconCount; i++) + { + guiIconsName[i] = (char *)RAYGUI_CALLOC(RAYGUI_ICON_MAX_NAME_LENGTH, sizeof(char)); + memcpy(guiIconsName[i], fileDataPtr, RAYGUI_ICON_MAX_NAME_LENGTH); + fileDataPtr += RAYGUI_ICON_MAX_NAME_LENGTH; + } + } + else + { + // Skip icon name data if not required + fileDataPtr += iconCount*RAYGUI_ICON_MAX_NAME_LENGTH; + } + + int iconDataSize = iconCount*((int)iconSize*(int)iconSize/32)*(int)sizeof(unsigned int); + guiIconsPtr = (unsigned int *)RAYGUI_CALLOC(iconDataSize, 1); + + memcpy(guiIconsPtr, fileDataPtr, iconDataSize); + } + + return guiIconsName; +} + +// Draw selected icon using rectangles pixel-by-pixel +void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color) +{ + if ((guiIconFontOffsetY > 0) && (iconId < RAYGUI_ICON_MAX_FONT_BACKED)) + { + int maxIconsPerLine = guiFont.texture.width/(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + int x = iconId%maxIconsPerLine; + int y = iconId/maxIconsPerLine; + + Rectangle srcRec = { (float)x*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + RAYGUI_ICON_FONT_ATLAS_PADDING, + guiIconFontOffsetY + (float)y*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + RAYGUI_ICON_FONT_ATLAS_PADDING, + RAYGUI_ICON_SIZE, RAYGUI_ICON_SIZE }; + Rectangle dstRec = { (float)posX, (float)posY, (float)pixelSize*RAYGUI_ICON_SIZE, (float)pixelSize*RAYGUI_ICON_SIZE }; + + DrawTexturePro(guiFont.texture, srcRec, dstRec, RAYGUI_CLITERAL(Vector2){ 0, 0 }, 0.0f, color); + } + else + { + #define BIT_CHECK(a,b) ((a) & (1u<<(b))) + + for (int i = 0, y = 0; i < RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32; i++) + { + for (int k = 0; k < 32; k++) + { + if (BIT_CHECK(guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i], k)) + { + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize, + (float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color); + } + + if ((k == 15) || (k == 31)) y++; + } + } + } +} + +// Set icon drawing size +void GuiSetIconScale(int scale) +{ + if (scale >= 1) guiIconScale = scale; +} + +// Get text width considering gui style and icon size (if required). +// For multi-line text (containing '\n'), returns the width of the widest line. +int GuiGetTextWidth(const char *text) +{ + if (text == NULL) return 0; + + int maxWidth = 0; + const char *linePtr = text; + + while ((linePtr[0] != '\0') && ((linePtr - text) < MAX_LINE_BUFFER_SIZE)) + { + int lineWidth = GetLineWidth(linePtr); + if (lineWidth > maxWidth) maxWidth = lineWidth; + + // Skip to the next '\n' (or end of string/buffer) + while ((linePtr[0] != '\0') && (linePtr[0] != '\n') && ((linePtr - text) < MAX_LINE_BUFFER_SIZE)) + { + linePtr++; + } + // Advance past the '\n' delimiter to the start of the next line + if (linePtr[0] == '\n') linePtr++; + } + + return maxWidth; +} + +#endif // !RAYGUI_NO_ICONS + +//---------------------------------------------------------------------------------- +// Module Internal Functions Definition +//---------------------------------------------------------------------------------- +// Get text line width (stops at '\n' or '\0') +// NOTE: Considers icon marker '#NNN#' +static int GetLineWidth(const char *text) +{ +#if !defined(RAYGUI_ICON_TEXT_PADDING) + #define RAYGUI_ICON_TEXT_PADDING 4 +#endif + + Vector2 textSize = { 0 }; + int textIconOffset = 0; + + if ((text != NULL) && (text[0] != '\0')) + { + // Icon marker: '#' + 1..3 digits + '#' (matches GetTextIcon()) + if (text[0] == '#') + { + int pos = 1; + while ((pos < 4) && (text[pos] >= '0') && (text[pos] <= '9')) pos++; + if (text[pos] == '#') textIconOffset = pos + 1; + } + + text += textIconOffset; + + // Make sure guiFont is set, GuiGetStyle() initializes it lazynessly + float fontSize = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + + // Custom MeasureText() implementation -- single line only + if ((guiFont.texture.id > 0) && (text != NULL)) + { + // Get size in bytes of the line, considering end of line and line break + int size = 0; + for (int i = 0; i < MAX_LINE_BUFFER_SIZE; i++) + { + if ((text[i] != '\0') && (text[i] != '\n')) size++; + else break; + } + + float scaleFactor = fontSize/(float)guiFont.baseSize; + textSize.y = (float)guiFont.baseSize*scaleFactor; + float glyphWidth = 0.0f; + + for (int i = 0, codepointSize = 0; i < size; i += codepointSize) + { + int codepoint = GetCodepointNext(&text[i], &codepointSize); + int codepointIndex = GetGlyphIndex(guiFont, codepoint); + + if (guiFont.glyphs[codepointIndex].advanceX == 0) glyphWidth = ((float)guiFont.recs[codepointIndex].width*scaleFactor); + else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor); + + textSize.x += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + } + } + + if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + RAYGUI_ICON_TEXT_PADDING); + } + + return (int)textSize.x; +} + +// Get text bounds considering control bounds +static Rectangle GetTextBounds(int control, Rectangle bounds) +{ + Rectangle textBounds = bounds; + + textBounds.x = bounds.x + GuiGetStyle(control, BORDER_WIDTH); + textBounds.y = bounds.y + GuiGetStyle(control, BORDER_WIDTH) + GuiGetStyle(control, TEXT_PADDING); + textBounds.width = bounds.width - 2*GuiGetStyle(control, BORDER_WIDTH) - 2*GuiGetStyle(control, TEXT_PADDING); + textBounds.height = bounds.height - 2*GuiGetStyle(control, BORDER_WIDTH) - 2*GuiGetStyle(control, TEXT_PADDING); // NOTE: Text is processed line per line! + + // Depending on control, TEXT_PADDING and TEXT_ALIGNMENT properties could affect the text-bounds + switch (control) + { + case COMBOBOX: + case DROPDOWNBOX: + case LISTVIEW: + // TODO: Special cases (no label): COMBOBOX, DROPDOWNBOX, LISTVIEW + case SLIDER: + case CHECKBOX: + case VALUEBOX: + case TABBAR: + // TODO: Special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER + default: + { + // WARNING: TEXT_ALIGNMENT is already considered in GuiDrawText() + if (GuiGetStyle(control, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT) textBounds.x -= GuiGetStyle(control, TEXT_PADDING); + else textBounds.x += GuiGetStyle(control, TEXT_PADDING); + } + break; + } + + return textBounds; +} + +// Get text icon if provided and move text cursor +// NOTE: Up to RAYGUI_ICON_MAX_ICONS supported for iconId +static const char *GetTextIcon(const char *text, int *iconId) +{ +#if !defined(RAYGUI_NO_ICONS) + *iconId = -1; + if (text[0] == '#') // Maybe an icon, if it starts with # but an ending # must be found + { + char iconValue[4] = { 0 }; // Maximum length for icon value: 3 digits + '\0' + + int pos = 1; + while ((pos < 4) && (text[pos] >= '0') && (text[pos] <= '9')) + { + iconValue[pos - 1] = text[pos]; + pos++; + } + + if (text[pos] == '#') + { + int rawIconId = TextToInteger(iconValue); + if (rawIconId < RAYGUI_ICON_MAX_ICONS) + { + *iconId = rawIconId; + + // Move text pointer after icon + // WARNING: If only icon provided, it could point to EOL character: '\0' + if (*iconId >= 0) text += (pos + 1); + } + } + } +#endif + + return text; +} + +// Get text divided into lines (by line-breaks '\n') +// WARNING: It returns pointers to new lines but it does not add NULL ('\0') terminator! +static const char **GetTextLines(const char *text, int *count) +{ + #define RAYGUI_MAX_TEXT_LINES 128 + + static const char *lines[RAYGUI_MAX_TEXT_LINES] = { 0 }; + for (int i = 0; i < RAYGUI_MAX_TEXT_LINES; i++) lines[i] = NULL; // Init NULL pointers to substrings + + int textLength = (int)strlen(text); + + lines[0] = text; + *count = 1; + + for (int i = 0; (i < textLength) && (*count < RAYGUI_MAX_TEXT_LINES); i++) + { + if ((text[i] == '\n') && ((i + 1) < textLength)) + { + lines[*count] = &text[i + 1]; + *count += 1; + } + } + + return lines; +} + +// Get text width to next space for provided string +static float GetNextSpaceWidth(const char *text, int *nextSpaceIndex) +{ + float width = 0; + int codepointByteCount = 0; + int codepoint = 0; + int index = 0; + float glyphWidth = 0; + float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize; + + for (int i = 0; text[i] != '\0'; i++) + { + if (text[i] != ' ') + { + codepoint = GetCodepoint(&text[i], &codepointByteCount); + index = GetGlyphIndex(guiFont, codepoint); + glyphWidth = (guiFont.glyphs[index].advanceX == 0)? guiFont.recs[index].width*scaleFactor : guiFont.glyphs[index].advanceX*scaleFactor; + width += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + } + else + { + *nextSpaceIndex = i; + break; + } + } + + return width; +} + +// Gui draw text using default font +static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint) +{ + #define TEXT_VALIGN_PIXEL_OFFSET(h) ((int)h%2) // Vertical alignment for pixel perfect + + #if !defined(RAYGUI_ICON_TEXT_PADDING) + #define RAYGUI_ICON_TEXT_PADDING 4 + #endif + + if ((text == NULL) || (text[0] == '\0')) return; // Security check + + // PROCEDURE: + // - Text is processed line per line + // - For every line, horizontal alignment is defined + // - For all text, vertical alignment is defined (multiline text only) + // - For every line, wordwrap mode is checked (useful for GuitextBox(), read-only) + + // Get text lines (using '\n' as delimiter) to be processed individually + // WARNING: GuiTextSplit() function can't be used now because it can have already been used + // before the GuiDrawText() call and its buffer is static, it would be overriden :( + int lineCount = 0; + const char **lines = GetTextLines(text, &lineCount); + + // Text style variables + //int alignment = GuiGetStyle(DEFAULT, TEXT_ALIGNMENT); + int alignmentVertical = GuiGetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL); + int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); // Wrap-mode only available in read-only mode, no for text editing + + // TODO: WARNING: This totalHeight is not valid for vertical alignment in case of word-wrap + float totalHeight = (float)(lineCount*GuiGetStyle(DEFAULT, TEXT_SIZE) + (lineCount - 1)*GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); + float posOffsetY = 0.0f; + + for (int i = 0; i < lineCount; i++) + { + int iconId = 0; + lines[i] = GetTextIcon(lines[i], &iconId); // Check text for icon and move cursor + + // Get text position depending on alignment and iconId + //--------------------------------------------------------------------------------- + Vector2 textBoundsPosition = { textBounds.x, textBounds.y }; + float textBoundsWidthOffset = 0.0f; + + // NOTE: Icon was already stripped above by GetTextIcon(); GetLineWidth() + // takes no icon path here and returns only the glyph width of this line. + int textSizeX = GetLineWidth(lines[i]); + + // If text requires an icon, add size to measure + if (iconId >= 0) + { + textSizeX += RAYGUI_ICON_SIZE*guiIconScale; + + // WARNING: If only icon provided, text could be pointing to EOF character: '\0' +#if !defined(RAYGUI_NO_ICONS) + if ((lines[i] != NULL) && (lines[i][0] != '\0')) textSizeX += RAYGUI_ICON_TEXT_PADDING; +#endif + } + + // Check guiTextAlign global variables + switch (alignment) + { + case TEXT_ALIGN_LEFT: textBoundsPosition.x = textBounds.x; break; + case TEXT_ALIGN_CENTER: textBoundsPosition.x = textBounds.x + textBounds.width/2 - textSizeX/2; break; + case TEXT_ALIGN_RIGHT: textBoundsPosition.x = textBounds.x + textBounds.width - textSizeX; break; + default: break; + } + + if (textSizeX > textBounds.width && (lines[i] != NULL) && (lines[i][0] != '\0')) textBoundsPosition.x = textBounds.x; + + switch (alignmentVertical) + { + // Only valid in case of wordWrap = 0; + case TEXT_ALIGN_TOP: textBoundsPosition.y = textBounds.y + posOffsetY; break; + case TEXT_ALIGN_MIDDLE: textBoundsPosition.y = textBounds.y + posOffsetY + textBounds.height/2 - totalHeight/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height); break; + case TEXT_ALIGN_BOTTOM: textBoundsPosition.y = textBounds.y + posOffsetY + textBounds.height - totalHeight + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height); break; + default: break; + } + + // NOTE: Make sure getting pixel-perfect coordinates, + // In case of decimals, it could result in text positioning artifacts + textBoundsPosition.x = (float)((int)textBoundsPosition.x); + textBoundsPosition.y = (float)((int)textBoundsPosition.y); + //--------------------------------------------------------------------------------- + + // Draw text (with icon if available) + //--------------------------------------------------------------------------------- +#if !defined(RAYGUI_NO_ICONS) + if (iconId >= 0) + { + // NOTE: Considering icon height, probably different than text size + GuiDrawIcon(iconId, (int)textBoundsPosition.x, (int)(textBounds.y + textBounds.height/2 - RAYGUI_ICON_SIZE*guiIconScale/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height)), guiIconScale, tint); + textBoundsPosition.x += (float)(RAYGUI_ICON_SIZE*guiIconScale + RAYGUI_ICON_TEXT_PADDING); + textBoundsWidthOffset = (float)(RAYGUI_ICON_SIZE*guiIconScale + RAYGUI_ICON_TEXT_PADDING); + } +#endif + // Get size in bytes of text, considering end of line and line break + int lineSize = 0; + for (int c = 0; (lines[i][c] != '\0') && (lines[i][c] != '\n') && (lines[i][c] != '\r'); c++, lineSize++){ } + float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize; + + int lastSpaceIndex = 0; + bool tempWrapCharMode = false; + + int textOffsetY = 0; + float textOffsetX = 0.0f; + float glyphWidth = 0; + + int ellipsisWidth = GuiGetTextWidth("..."); + bool textOverflow = false; + for (int c = 0, codepointSize = 0; c < lineSize; c += codepointSize) + { + int codepoint = GetCodepointNext(&lines[i][c], &codepointSize); + int index = GetGlyphIndex(guiFont, codepoint); + + // NOTE: Normally, exiting the decoding sequence as soon as a bad byte is found (and return 0x3f) + // but all of the bad bytes need to be drawn using the '?' symbol, moving one byte + if (codepoint == 0x3f) codepointSize = 1; // WARNING: Not recognized codepoints size + + // Get glyph width to check if it goes out of bounds + if (guiFont.glyphs[index].advanceX == 0) glyphWidth = ((float)guiFont.recs[index].width*scaleFactor); + else glyphWidth = (float)guiFont.glyphs[index].advanceX*scaleFactor; + + // Wrap mode text measuring, to validate if + // it can be drawn or a new line is required + if (wrapMode == TEXT_WRAP_CHAR) + { + // Jump to next line if current character reach end of the box limits + if ((textOffsetX + glyphWidth) > textBounds.width - textBoundsWidthOffset) + { + textOffsetX = 0.0f; + textOffsetY += (GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); + + if (tempWrapCharMode) // Wrap at char level when too long words + { + wrapMode = TEXT_WRAP_WORD; + tempWrapCharMode = false; + } + } + } + else if (wrapMode == TEXT_WRAP_WORD) + { + if (codepoint == 32) lastSpaceIndex = c; + + // Get width to next space in line + int nextSpaceIndex = 0; + float nextSpaceWidth = GetNextSpaceWidth(lines[i] + c, &nextSpaceIndex); + + int nextSpaceIndex2 = 0; + float nextWordSize = GetNextSpaceWidth(lines[i] + lastSpaceIndex + 1, &nextSpaceIndex2); + + if (nextWordSize > textBounds.width - textBoundsWidthOffset) + { + // Considering the case the next word is longer than bounds + tempWrapCharMode = true; + wrapMode = TEXT_WRAP_CHAR; + } + else if ((textOffsetX + nextSpaceWidth) > textBounds.width - textBoundsWidthOffset) + { + textOffsetX = 0.0f; + textOffsetY += (GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); + } + } + + if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint + else + { + // WARNING: There are multiple types of spaces in Unicode, + // maybe it's a good idea to add support for more: http://jkorpela.fi/chars/spaces.html + if ((codepoint != ' ') && (codepoint != '\t')) // Do not draw codepoints with no glyph + { + if (wrapMode == TEXT_WRAP_NONE) + { + // Draw only required text glyphs fitting the textBounds.width + if (textSizeX > textBounds.width) + { + if (textOffsetX <= (textBounds.width - glyphWidth - textBoundsWidthOffset - ellipsisWidth)) + { + DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); + } + else if (!textOverflow) + { + textOverflow = true; + + for (int j = 0; j < ellipsisWidth; j += ellipsisWidth/3) + { + DrawTextCodepoint(guiFont, '.', RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX + j, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); + } + } + } + else + { + DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); + } + } + else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) + { + // Draw only glyphs inside the bounds + if ((textBoundsPosition.y + textOffsetY) <= (textBounds.y + textBounds.height - GuiGetStyle(DEFAULT, TEXT_SIZE))) + { + DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); + } + } + } + + if (guiFont.glyphs[index].advanceX == 0) textOffsetX += ((float)guiFont.recs[index].width*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + else textOffsetX += ((float)guiFont.glyphs[index].advanceX*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + } + } + + if (wrapMode == TEXT_WRAP_NONE) posOffsetY += (float)(GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); + else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) + posOffsetY += (textOffsetY + GuiGetStyle(DEFAULT, TEXT_SIZE)); + //--------------------------------------------------------------------------------- + } + +#if defined(RAYGUI_DEBUG_TEXT_BOUNDS) + GuiDrawRectangle(textBounds, 0, WHITE, Fade(BLUE, 0.4f)); +#endif +} + +// Gui draw rectangle using default raygui plain style with borders +static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color) +{ + if (color.a > 0) + { + // Draw rectangle filled with color + DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, GuiFade(color, guiAlpha)); + } + + if (borderWidth > 0) + { + // Draw rectangle border lines with color + DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, borderWidth, GuiFade(borderColor, guiAlpha)); + DrawRectangle((int)rec.x, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, GuiFade(borderColor, guiAlpha)); + DrawRectangle((int)rec.x + (int)rec.width - borderWidth, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, GuiFade(borderColor, guiAlpha)); + DrawRectangle((int)rec.x, (int)rec.y + (int)rec.height - borderWidth, (int)rec.width, borderWidth, GuiFade(borderColor, guiAlpha)); + } + +#if defined(RAYGUI_DEBUG_RECS_BOUNDS) + DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, Fade(RED, 0.4f)); +#endif +} + +// Draw tooltip using control bounds +static void GuiTooltip(Rectangle controlRec) +{ + if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiControlExclusiveMode) + { + Vector2 textSize = MeasureTextEx(guiFont, guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + + if ((controlRec.x + textSize.x + 16) > GetScreenWidth()) controlRec.x -= (textSize.x + 16 - controlRec.width); + + int lineCount = 0; + GetTextLines(guiTooltipPtr, &lineCount); // Only using the line count + if ((controlRec.y + controlRec.height + textSize.y + 4 + 8*lineCount) > GetScreenHeight()) + controlRec.y -= (controlRec.height + textSize.y + 4 + 8*lineCount); + + // TODO: Probably TEXT_LINE_SPACING should be considered on panel size instead of hardcoding 8.0f + GuiPanel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, textSize.y + 8.0f*lineCount }, NULL); + + int textPadding = GuiGetStyle(LABEL, TEXT_PADDING); + int textAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); + GuiSetStyle(LABEL, TEXT_PADDING, 0); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + GuiLabel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, textSize.y + 8.0f*lineCount }, guiTooltipPtr); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, textAlignment); + GuiSetStyle(LABEL, TEXT_PADDING, textPadding); + } +} + +// Scroll bar control (used by GuiScrollPanel()) +static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) +{ + GuiState state = guiState; + + // Is the scrollbar horizontal or vertical? + bool isVertical = (bounds.width > bounds.height)? false : true; + + // The size (width or height depending on scrollbar type) of the spinner buttons + const int spinnerSize = GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)? + (isVertical? (int)bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) : + (int)bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0; + + // Arrow buttons [<] [>] [∧] [∨] + Rectangle arrowUpLeft = { 0 }; + Rectangle arrowDownRight = { 0 }; + + // Actual area of the scrollbar excluding the arrow buttons + Rectangle scrollbar = { 0 }; + + // Slider bar that moves --[///]----- + Rectangle slider = { 0 }; + + // Normalize value + if (value > maxValue) value = maxValue; + if (value < minValue) value = minValue; + + int valueRange = maxValue - minValue; + if (valueRange <= 0) valueRange = 1; + + int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); + if (sliderSize < 1) sliderSize = 1; // Consider a minimum slider size of 1 pixel + + // Calculate rectangles for all of the components + arrowUpLeft = RAYGUI_CLITERAL(Rectangle){ + (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), + (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), + (float)spinnerSize, (float)spinnerSize }; + + if (isVertical) + { + arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + bounds.height - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; + scrollbar = RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), arrowUpLeft.y + arrowUpLeft.height, bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)), bounds.height - arrowUpLeft.height - arrowDownRight.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) }; + + // Make sure the slider won't get outside of the scrollbar + sliderSize = (sliderSize >= scrollbar.height)? ((int)scrollbar.height - 2) : sliderSize; + slider = RAYGUI_CLITERAL(Rectangle){ + bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), + scrollbar.y + (int)(((float)(value - minValue)/valueRange)*(scrollbar.height - sliderSize)), + bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)), + (float)sliderSize }; + } + else // horizontal + { + arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; + scrollbar = RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x + arrowUpLeft.width, bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), bounds.width - arrowUpLeft.width - arrowDownRight.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)) }; + + // Make sure the slider won't get outside of the scrollbar + sliderSize = (sliderSize >= scrollbar.width)? ((int)scrollbar.width - 2) : sliderSize; + slider = RAYGUI_CLITERAL(Rectangle){ + scrollbar.x + (int)(((float)(value - minValue)/valueRange)*(scrollbar.width - sliderSize)), + bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), + (float)sliderSize, + bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)) }; + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (GUI_BUTTON_DOWN && + !CheckCollisionPointRec(mousePoint, arrowUpLeft) && + !CheckCollisionPointRec(mousePoint, arrowDownRight)) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + state = STATE_PRESSED; + + if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); + else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + + // Handle mouse wheel + float scrollDelta = GUI_SCROLL_DELTA; + if (scrollDelta != 0) value += (int)scrollDelta; + + // Handle mouse button down + if (GUI_BUTTON_PRESSED) + { + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + + // Check arrows click + if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + else if (!CheckCollisionPointRec(mousePoint, slider)) + { + // If click on scrollbar position but not on slider, place slider directly on that position + if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); + else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); + } + + state = STATE_PRESSED; + } + + // Keyboard control on mouse hover scrollbar + /* + if (isVertical) + { + if (GUI_KEY_DOWN(KEY_DOWN)) value += 5; + else if (GUI_KEY_DOWN(KEY_UP)) value -= 5; + } + else + { + if (GUI_KEY_DOWN(KEY_RIGHT)) value += 5; + else if (GUI_KEY_DOWN(KEY_LEFT)) value -= 5; + } + */ + } + + // Normalize value + if (value > maxValue) value = maxValue; + if (value < minValue) value = minValue; + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED))); // Draw the background + + GuiDrawRectangle(scrollbar, 0, BLANK, GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL))); // Draw the scrollbar active area background + GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BORDER + state*3))); // Draw the slider bar + + // Draw arrows (using icon if available) + if (GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)) + { +#if defined(RAYGUI_NO_ICONS) + GuiDrawText(isVertical? "^" : "<", + RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); + GuiDrawText(isVertical? "v" : ">", + RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); +#else + GuiDrawText(isVertical? GuiIconText(ICON_ARROW_UP_FILL, NULL) : GuiIconText(ICON_ARROW_LEFT_FILL, NULL), + RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_UP_FILL / ICON_ARROW_LEFT_FILL + GuiDrawText(isVertical? GuiIconText(ICON_ARROW_DOWN_FILL, NULL) : GuiIconText(ICON_ARROW_RIGHT_FILL, NULL), + RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_DOWN_FILL / ICON_ARROW_RIGHT_FILL +#endif + } + //-------------------------------------------------------------------- + + return value; +} + +// Update font image atlas to append raygui icons +static int GuiFontIconBaking(Image *imFont, Font font, Rectangle *whiteRec) +{ + int iconOffsetY = 0; + + // Check max glyph rec y bottom position in the atlas image, + // to start drawing icons below that line + int maxGlyphRecY = 0; + for (int i = 0; i < font.glyphCount; i++) + { + if ((font.recs[i].y + font.recs[i].height) > maxGlyphRecY) + maxGlyphRecY = (int)font.recs[i].y + (int)font.recs[i].height; + } + + int maxIconsPerLine = imFont->width/(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + int reqIconLines = RAYGUI_ICON_MAX_FONT_BACKED/maxIconsPerLine + RAYGUI_ICON_MAX_FONT_BACKED%maxIconsPerLine + 1; // One extra line + int reqHeight = reqIconLines*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + + // Check if image requires scaling and how much + if ((maxGlyphRecY + reqHeight) > imFont->height) + { + int newImHeight = 1; + while (newImHeight < (maxGlyphRecY + reqHeight)) newImHeight <<= 1; // Round to next POT + + char *newImData = (char *)RL_CALLOC(imFont->width*newImHeight*2, sizeof(char)); + memcpy(newImData, imFont->data, imFont->width*imFont->height*2); + RL_FREE(imFont->data); + + // Clear imFont bottom-right corner rec + for (int y = 0; y < 4; y++) + for (int x = 0; x < 4; x++) + ((unsigned short *)newImData)[(imFont->height - y - 1)*imFont->width + imFont->width - x - 1] = 0x0000; + + imFont->data = newImData; + imFont->height = newImHeight; + + // Set new image white corner and new white rec + for (int y = 0; y < 3; y++) + for (int x = 0; x < 3; x++) + ((unsigned short *)newImData)[(imFont->height - y - 1)*imFont->width + imFont->width - x - 1] = 0xffff; + + *whiteRec = RAYGUI_CLITERAL(Rectangle){ (float)imFont->width - 2, (float)imFont->height - 2, 1, 1 }; + } + + // Calculate image offset positions to start drawing + // NOTE: For Y, look for a multiple of icon size + 2*padding, for better alignment + int offsetX = RAYGUI_ICON_FONT_ATLAS_PADDING; + int offsetY = ((maxGlyphRecY + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING - 1))/ + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING))*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + + RAYGUI_ICON_FONT_ATLAS_PADDING; + + iconOffsetY = offsetY - RAYGUI_ICON_FONT_ATLAS_PADDING; + unsigned short *pixels = (unsigned short *)imFont->data; + + #define BIT_CHECK(a,b) ((a) & (1u<<(b))) + + for (int iconId = 0; iconId < RAYGUI_ICON_MAX_FONT_BACKED; iconId++) + { + // Wrap to next line if next icon won't fit + if ((offsetX + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING)) > imFont->width) + { + offsetX = RAYGUI_ICON_FONT_ATLAS_PADDING; + offsetY += RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING; + } + + for (int i = 0, y = 0; i < RAYGUI_ICON_DATA_ELEMENTS; i++) + { + unsigned int data = guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i]; + + for (int k = 0; k < 32; k++) + { + pixels[(offsetY + y)*imFont->width + offsetX + k%16] = (BIT_CHECK(data, k))? 0xffff : 0x00ff; + + if ((k == 15) || (k == 31)) y++; + } + } + + // Update current icon X position + offsetX += (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + } + + return iconOffsetY; +} + +// Split controls text into multiple strings +// NOTE: Re-used by GuiToggleSlider(), GuiComboBox(), GuiDropdownBox(), GuiListView(), GuiMessageBox(), GuiInputBox() +static char **GuiTextSplit(const char *text, char delimiter, int *count) +{ + // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) + // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, + // all used memory is static... it has some limitations: + // 1. Maximum number of possible split strings is set by RAYGUI_TEXTSPLIT_MAX_ITEMS + // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE + // NOTE: Those definitions could be externally provided if required + + #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS) + #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128 + #endif + #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE) + #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 // WARNING: Max expected size for all concat items + #endif + + static char *itemPtrs[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { 0 }; // String pointers array (points to buffer data) + static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; // Buffer data (text input copy with '\0' added) + memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE); + + itemPtrs[0] = buffer; + int itemCounter = 1; + + // Count how many substrings text contains and point to every one of them + for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++) + { + buffer[i] = text[i]; + if (buffer[i] == '\0') break; + else if ((buffer[i] == delimiter) || (buffer[i] == '\n')) + { + itemPtrs[itemCounter] = buffer + i + 1; + buffer[i] = '\0'; // Set terminator for current item + + itemCounter++; + if (itemCounter >= RAYGUI_TEXTSPLIT_MAX_ITEMS) break; + } + } + + *count = itemCounter; + return itemPtrs; +} + +// Convert color data from RGB to HSV +// NOTE: Color data should be passed normalized +static Vector3 ConvertRGBtoHSV(Vector3 rgb) +{ + Vector3 hsv = { 0 }; + float min = 0.0f; + float max = 0.0f; + float delta = 0.0f; + + min = (rgb.x < rgb.y)? rgb.x : rgb.y; + min = (min < rgb.z)? min : rgb.z; + + max = (rgb.x > rgb.y)? rgb.x : rgb.y; + max = (max > rgb.z)? max : rgb.z; + + hsv.z = max; // Value + delta = max - min; + + if (delta < 0.00001f) + { + hsv.y = 0.0f; + hsv.x = 0.0f; // Undefined, maybe NAN? + return hsv; + } + + if (max > 0.0f) + { + // NOTE: If max is 0, this divide would cause a crash + hsv.y = (delta/max); // Saturation + } + else + { + // NOTE: If max is 0, then r = g = b = 0, s = 0, h is undefined + hsv.y = 0.0f; + hsv.x = 0.0f; // Undefined, maybe NAN? + return hsv; + } + + // NOTE: Comparing float values could not work properly + if (rgb.x >= max) hsv.x = (rgb.y - rgb.z)/delta; // Between yellow & magenta + else + { + if (rgb.y >= max) hsv.x = 2.0f + (rgb.z - rgb.x)/delta; // Between cyan & yellow + else hsv.x = 4.0f + (rgb.x - rgb.y)/delta; // Between magenta & cyan + } + + hsv.x *= 60.0f; // Convert to degrees + + if (hsv.x < 0.0f) hsv.x += 360.0f; + + return hsv; +} + +// Convert color data from HSV to RGB +// NOTE: Color data should be passed normalized +static Vector3 ConvertHSVtoRGB(Vector3 hsv) +{ + Vector3 rgb = { 0 }; + float hh = 0.0f, p = 0.0f, q = 0.0f, t = 0.0f, ff = 0.0f; + long i = 0; + + // NOTE: Comparing float values could not work properly + if (hsv.y <= 0.0f) + { + rgb.x = hsv.z; + rgb.y = hsv.z; + rgb.z = hsv.z; + return rgb; + } + + hh = hsv.x; + if (hh >= 360.0f) hh = 0.0f; + hh /= 60.0f; + + i = (long)hh; + ff = hh - i; + p = hsv.z*(1.0f - hsv.y); + q = hsv.z*(1.0f - (hsv.y*ff)); + t = hsv.z*(1.0f - (hsv.y*(1.0f - ff))); + + switch (i) + { + case 0: + { + rgb.x = hsv.z; + rgb.y = t; + rgb.z = p; + } break; + case 1: + { + rgb.x = q; + rgb.y = hsv.z; + rgb.z = p; + } break; + case 2: + { + rgb.x = p; + rgb.y = hsv.z; + rgb.z = t; + } break; + case 3: + { + rgb.x = p; + rgb.y = q; + rgb.z = hsv.z; + } break; + case 4: + { + rgb.x = t; + rgb.y = p; + rgb.z = hsv.z; + } break; + case 5: + default: + { + rgb.x = hsv.z; + rgb.y = p; + rgb.z = q; + } break; + } + + return rgb; +} + +// Color fade-in or fade-out, alpha goes from 0.0f to 1.0f +// WARNING: It multiplies current alpha by alpha scale factor, +// raylib Fade() multiplies alpha by 255.0f +static Color GuiFade(Color color, float alpha) +{ + if (alpha < 0.0f) alpha = 0.0f; + else if (alpha > 1.0f) alpha = 1.0f; + + Color result = { color.r, color.g, color.b, (unsigned char)(color.a*alpha) }; + + return result; +} + +#if defined(RAYGUI_STANDALONE) +// Returns a Color struct from hexadecimal value +static Color GetColor(int hexValue) +{ + Color color; + + color.r = (unsigned char)(hexValue >> 24) & 0xff; + color.g = (unsigned char)(hexValue >> 16) & 0xff; + color.b = (unsigned char)(hexValue >> 8) & 0xff; + color.a = (unsigned char)hexValue & 0xff; + + return color; +} + +// Get color with alpha applied, alpha goes from 0.0f to 1.0f +static Color Fade(Color color, float alpha) +{ + Color result = color; + + if (alpha < 0.0f) alpha = 0.0f; + else if (alpha > 1.0f) alpha = 1.0f; + + result.a = (unsigned char)(255.0f*alpha); + + return result; +} + +// Returns hexadecimal value for a Color +static int ColorToInt(Color color) +{ + return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a); +} + +// Check if point is inside rectangle +static bool CheckCollisionPointRec(Vector2 point, Rectangle rec) +{ + bool collision = false; + + if ((point.x >= rec.x) && (point.x <= (rec.x + rec.width)) && + (point.y >= rec.y) && (point.y <= (rec.y + rec.height))) collision = true; + + return collision; +} + +// Formatting of text with variables to 'embed' +static const char *TextFormat(const char *text, ...) +{ + #if !defined(RAYGUI_TEXTFORMAT_MAX_SIZE) + #define RAYGUI_TEXTFORMAT_MAX_SIZE 256 + #endif + + static char buffer[RAYGUI_TEXTFORMAT_MAX_SIZE] = { 0 }; + memset(buffer, 0, RAYGUI_TEXTFORMAT_MAX_SIZE); + + va_list args; + va_start(args, text); + vsnprintf(buffer, RAYGUI_TEXTFORMAT_MAX_SIZE, text, args); + va_end(args); + + return buffer; +} + +// Get integer value from text +// NOTE: This function replaces atoi() [stdlib.h] +static int TextToInteger(const char *text) +{ + int value = 0; + int sign = 1; + + if ((text[0] == '+') || (text[0] == '-')) + { + if (text[0] == '-') sign = -1; + text++; + } + + for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10 + (int)(text[i] - '0'); + + return value*sign; +} + +// Get float value from text +// NOTE: This function replaces atof() [stdlib.h] +// WARNING: Only '.' character is understood as decimal point +static float TextToFloat(const char *text) +{ + float value = 0.0f; + float sign = 1.0f; + + if ((text[0] == '+') || (text[0] == '-')) + { + if (text[0] == '-') sign = -1.0f; + text++; + } + + int i = 0; + for (; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10.0f + (float)(text[i] - '0'); + + if (text[i++] != '.') value *= sign; + else + { + float divisor = 10.0f; + for (; ((text[i] >= '0') && (text[i] <= '9')); i++) + { + value += ((float)(text[i] - '0'))/divisor; + divisor = divisor*10.0f; + } + } + + return value; +} + +// Encode codepoint into UTF-8 text (char array size returned as parameter) +static const char *CodepointToUTF8(int codepoint, int *byteSize) +{ + static char utf8[6] = { 0 }; + int size = 0; + + if (codepoint <= 0x7f) + { + utf8[0] = (char)codepoint; + size = 1; + } + else if (codepoint <= 0x7ff) + { + utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0); + utf8[1] = (char)((codepoint & 0x3f) | 0x80); + size = 2; + } + else if (codepoint <= 0xffff) + { + utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0); + utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80); + utf8[2] = (char)((codepoint & 0x3f) | 0x80); + size = 3; + } + else if (codepoint <= 0x10ffff) + { + utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0); + utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80); + utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80); + utf8[3] = (char)((codepoint & 0x3f) | 0x80); + size = 4; + } + + *byteSize = size; + + return utf8; +} + +// Get next codepoint in a UTF-8 encoded text, scanning until '\0' is found +// When a invalid UTF-8 byte is encountered, exiting as soon as possible and returning a '?'(0x3f) codepoint +// Total number of bytes processed are returned as a parameter +// NOTE: The standard says U+FFFD should be returned in case of errors +// but that character is not supported by the default font in raylib +static int GetCodepointNext(const char *text, int *codepointSize) +{ + const char *ptr = text; + int codepoint = 0x3f; // Codepoint (defaults to '?') + *codepointSize = 1; + + // Get current codepoint and bytes processed + if (0xf0 == (0xf8 & ptr[0])) + { + // 4 byte UTF-8 codepoint + if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80) || ((ptr[3] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks + codepoint = ((0x07 & ptr[0]) << 18) | ((0x3f & ptr[1]) << 12) | ((0x3f & ptr[2]) << 6) | (0x3f & ptr[3]); + *codepointSize = 4; + } + else if (0xe0 == (0xf0 & ptr[0])) + { + // 3 byte UTF-8 codepoint + if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks + codepoint = ((0x0f & ptr[0]) << 12) | ((0x3f & ptr[1]) << 6) | (0x3f & ptr[2]); + *codepointSize = 3; + } + else if (0xc0 == (0xe0 & ptr[0])) + { + // 2 byte UTF-8 codepoint + if ((ptr[1] & 0xC0) ^ 0x80) { return codepoint; } //10xxxxxx checks + codepoint = ((0x1f & ptr[0]) << 6) | (0x3f & ptr[1]); + *codepointSize = 2; + } + else if (0x00 == (0x80 & ptr[0])) + { + // 1 byte UTF-8 codepoint + codepoint = ptr[0]; + *codepointSize = 1; + } + + return codepoint; +} +#endif // RAYGUI_STANDALONE + +#endif // RAYGUI_IMPLEMENTATION diff --git a/examples/textures/raygui.h b/examples/textures/raygui.h new file mode 100644 index 000000000..f7a116150 --- /dev/null +++ b/examples/textures/raygui.h @@ -0,0 +1,6460 @@ +/******************************************************************************************* +* +* raygui v5.0 - A simple and easy-to-use immediate-mode gui library +* +* DESCRIPTION: +* raygui is a tools-dev-focused immediate-mode-gui library based on raylib but also +* available as a standalone library, as long as input and drawing functions are provided +* +* FEATURES: +* - Immediate-mode gui, minimal retained data +* - +25 controls provided (basic and advanced) +* - Styling system for colors, font and metrics +* - Icons supported, embedded as a 1-bit icons pack +* - Standalone mode option (custom input/graphics backend) +* - Multiple support tools provided for raygui development +* +* POSSIBLE IMPROVEMENTS: +* - Better standalone mode API for easy plug of custom backends +* - Externalize required inputs, allow user easier customization +* +* LIMITATIONS: +* - No editable multi-line word-wraped text box supported +* - No auto-layout mechanism, up to the user to define controls position and size +* - Standalone mode requires library modification and some user work to plug another backend +* +* NOTES: +* - WARNING: GuiLoadStyle() and GuiLoadStyle{Custom}() functions, allocate memory for +* font atlas recs and glyphs, freeing that memory is (usually) up to the user, +* no unload function is explicitly provided... but note that GuiLoadStyleDefault() unloads +* by default any previously loaded font (texture, recs, glyphs) +* - Global UI alpha (guiAlpha) is applied inside GuiDrawRectangle() and GuiDrawText() functions +* +* CONTROLS PROVIDED: +* # Container/separators Controls +* - WindowBox --> StatusBar, Panel +* - GroupBox --> Line +* - Line +* - Panel --> StatusBar +* - ScrollPanel --> StatusBar +* - TabBar --> Toggle, Button +* +* # Basic Controls +* - Label +* - LabelButton --> Label +* - Button +* - Toggle +* - ToggleGroup --> Toggle +* - ToggleSlider +* - CheckBox +* - ComboBox +* - DropdownBox +* - TextBox +* - ValueBox --> TextBox +* - Spinner --> Button, ValueBox +* - Slider +* - SliderBar --> Slider +* - ProgressBar +* - StatusBar +* - DummyRec +* - Grid +* +* # Advance Controls +* - ListView +* - ColorPicker --> ColorPanel, ColorBarHue +* - MessageBox --> Window, Label, Button +* - TextInputBox --> Window, Label, TextBox, Button +* +* It also provides a set of functions for styling the controls based on its properties (size, color) +* +* +* RAYGUI STYLE (guiStyle): +* raygui uses a global data array for all gui style properties (allocated on data segment by default), +* when a new style is loaded, it is loaded over the global style... but a default gui style could always be +* recovered with GuiLoadStyleDefault() function, that overwrites the current style to the default one +* +* The global style array size is fixed and depends on the number of controls and properties: +* +* static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)]; +* +* guiStyle size is by default: 16*(16 + 8) = 384 int = 384*4 bytes = 1536 bytes = 1.5 KB +* +* Note that the first set of BASE properties (by default guiStyle[0..15]) belong to the generic style +* used for all controls, when any of those base values is set, it is automatically populated to all +* controls, so, specific control values overwriting generic style should be set after base values +* +* After the first BASE properties set, the EXTENDED properties set is defined (by default guiStyle[16..23]), +* those properties are actually common to all controls and can not be overwritten individually (like BASE ones) +* Some of those properties are: TEXT_SIZE, TEXT_SPACING, LINE_COLOR, BACKGROUND_COLOR +* +* Custom control properties can be defined using the EXTENDED properties for each independent control. +* +* TOOL: rGuiStyler is a visual tool to customize raygui style: github.com/raysan5/rguistyler +* +* +* RAYGUI ICONS (guiIcons): +* raygui could use a global array containing icons data (allocated on data segment by default), +* a custom icons set could be loaded over this array using GuiLoadIcons(), but loaded icons set +* must be same RAYGUI_ICON_SIZE and no more than RAYGUI_ICON_MAX_ICONS will be loaded +* +* Every icon is codified in binary form, using 1 bit per pixel, so, every 16x16 icon +* requires 8 integers (16*16/32) to be stored in memory. +* +* When the icon is draw, actually one quad per pixel is drawn if the bit for that pixel is set +* +* The global icons array size is fixed and depends on the number of icons and size: +* +* static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS]; +* +* guiIcons size is by default: 256*(16*16/32) = 2048*4 = 8192 bytes = 8 KB +* +* TOOL: rGuiIcons is a visual tool to customize/create raygui icons: github.com/raysan5/rguiicons +* +* RAYGUI LAYOUT: +* raygui currently does not provide an auto-layout mechanism like other libraries, +* layouts must be defined manually on controls drawing, providing the right bounds Rectangle for it +* +* TOOL: rGuiLayout is a visual tool to create raygui layouts: github.com/raysan5/rguilayout +* +* CONFIGURATION: +* #define RAYGUI_IMPLEMENTATION +* Generates the implementation of the library into the included file +* If not defined, the library is in header only mode and can be included in other headers +* or source files without problems. But only ONE file should hold the implementation +* +* #define RAYGUI_STANDALONE +* Avoid raylib.h header inclusion in this file. Data types defined on raylib are defined +* internally in the library and input management and drawing functions must be provided by +* the user (check library implementation for further details) +* +* #define RAYGUI_NO_ICONS +* Avoid including embedded ricons data (256 icons, 16x16 pixels, 1-bit per pixel, 2KB) +* +* #define RAYGUI_CUSTOM_ICONS +* Includes custom ricons.h header defining a set of custom icons, +* this file can be generated using rGuiIcons tool +* +* #define RAYGUI_FONT_ICONS_BAKING +* On gui font loading from style file, append the icons to font atlas image, so, +* icons can be drawn along the text as a texture, instead of using shapes to draw them +* +* #define RAYGUI_DEBUG_RECS_BOUNDS +* Draw control bounds rectangles for debug +* +* #define RAYGUI_DEBUG_TEXT_BOUNDS +* Draw text bounds rectangles for debug +* +* VERSIONS HISTORY: +* 5.0 (20-Jul-2026) ADDED: NEW control: GuiTabBar() +* ADDED: Support up to 512 icons (v500) +* ADDED: Support icons baking into font atlas image +* ADDED: guiControlExclusiveMode and guiControlExclusiveRec for exclusive modes +* ADDED: GuiValueBoxFloat(), with floats support +* ADDED: GuiDropdonwBox() properties: DROPDOWN_ARROW_HIDDEN, DROPDOWN_ROLL_UP +* ADDED: GuiListView() property: LIST_ITEMS_BORDER_WIDTH +* ADDED: GuiLoadIconsFromMemory(), used by GuiLoadIcons() +* ADDED: Macros for inputs customization, raylib decoupling +* ADDED: Control result return values: 1-RESULT_PRESSED, 2-RESULT_CHANGED, >2-Control_custom +* REMOVED: GuiSpinner() from controls list, using BUTTON + VALUEBOX properties +* REMOVED: GuiSliderPro(), functionality was redundant +* REMOVED: TextSplit() raylib function requirement on RAYGUI_STANDALONE +* REDESIGNED: WARNING: GuiLoadStyleFromMemory() to support icons baking into font atlas +* REDESIGNED: GuiToggleGroup() to process rows/cols with no need for GuiTextSplit() +* REDESIGNED: GuiColorPanel(), improved HSV <-> RGBA convertion +* REDESIGNED: WARNING: TEXT_LINE_SPACING does not consider text height, only lines spacing +* REDESIGNED: WARNING: GuiMessageBox(), added parameter for btn return, unify result +* REDESIGNED: WARNING: GuiTextInputBox(), added parameter for btn return, unify result +* REVIEWED: GuiLoadIconsFromMemory(), fixed memory issues +* REVIEWED: Controls using text labels to use LABEL properties +* REVIEWED: Replaced sprintf() by snprintf() for more safety +* REVIEWED: GuiTabBar(), close tab with mouse middle button +* REVIEWED: GuiScrollPanel(), scroll speed proportional to content +* REVIEWED: GuiDropdownBox(), support roll up and hidden arrow +* REVIEWED: GuiTextBox(), cursor position initialization +* REVIEWED: GuiSliderPro(), control value change check +* REVIEWED: GuiGrid(), simplified implementation +* REVIEWED: GuiIconText(), increase buffer size and reviewed padding +* REVIEWED: GuiDrawText(), improved wrap mode drawing +* REVIEWED: GuiScrollBar(), minor tweaks +* REVIEWED: GuiProgressBar(), improved borders computing +* REVIEWED: GuiTextBox(), multiple improvements: autocursor and more +* REVIEWED: Functions descriptions, removed wrong return value reference +* +* 4.0 (12-Sep-2023) ADDED: GuiToggleSlider() +* ADDED: GuiColorPickerHSV() and GuiColorPanelHSV() +* ADDED: Multiple new icons, mostly compiler related +* ADDED: New DEFAULT properties: TEXT_LINE_SPACING, TEXT_ALIGNMENT_VERTICAL, TEXT_WRAP_MODE +* ADDED: New enum values: GuiTextAlignment, GuiTextAlignmentVertical, GuiTextWrapMode +* ADDED: Support loading styles with custom font charset from external file +* REDESIGNED: GuiTextBox(), support mouse cursor positioning +* REDESIGNED: GuiDrawText(), support multiline and word-wrap modes (read only) +* REDESIGNED: GuiProgressBar() to be more visual, progress affects border color +* REDESIGNED: Global alpha consideration moved to GuiDrawRectangle() and GuiDrawText() +* REDESIGNED: GuiScrollPanel(), get parameters by reference and return result value +* REDESIGNED: GuiToggleGroup(), get parameters by reference and return result value +* REDESIGNED: GuiComboBox(), get parameters by reference and return result value +* REDESIGNED: GuiCheckBox(), get parameters by reference and return result value +* REDESIGNED: GuiSlider(), get parameters by reference and return result value +* REDESIGNED: GuiSliderBar(), get parameters by reference and return result value +* REDESIGNED: GuiProgressBar(), get parameters by reference and return result value +* REDESIGNED: GuiListView(), get parameters by reference and return result value +* REDESIGNED: GuiColorPicker(), get parameters by reference and return result value +* REDESIGNED: GuiColorPanel(), get parameters by reference and return result value +* REDESIGNED: GuiColorBarAlpha(), get parameters by reference and return result value +* REDESIGNED: GuiColorBarHue(), get parameters by reference and return result value +* REDESIGNED: GuiGrid(), get parameters by reference and return result value +* REDESIGNED: GuiGrid(), added extra parameter +* REDESIGNED: GuiListViewEx(), change parameters order +* REDESIGNED: All controls return result as int value +* REVIEWED: GuiScrollPanel() to avoid smallish scroll-bars +* REVIEWED: All examples and specially controls_test_suite +* RENAMED: gui_file_dialog module to gui_window_file_dialog +* UPDATED: All styles to include ISO-8859-15 charset (as much as possible) +* +* 3.6 (10-May-2023) ADDED: New icon: SAND_TIMER +* ADDED: GuiLoadStyleFromMemory() (binary only) +* REVIEWED: GuiScrollBar() horizontal movement key +* REVIEWED: GuiTextBox() crash on cursor movement +* REVIEWED: GuiTextBox(), additional inputs support +* REVIEWED: GuiLabelButton(), avoid text cut +* REVIEWED: GuiTextInputBox(), password input +* REVIEWED: Local GetCodepointNext(), aligned with raylib +* REDESIGNED: GuiSlider*()/GuiScrollBar() to support out-of-bounds +* +* 3.5 (20-Apr-2023) ADDED: GuiTabBar(), based on GuiToggle() +* ADDED: Helper functions to split text in separate lines +* ADDED: Multiple new icons, useful for code editing tools +* REMOVED: Unneeded icon editing functions +* REMOVED: GuiTextBoxMulti(), very limited and broken +* REMOVED: MeasureTextEx() dependency, logic directly implemented +* REMOVED: DrawTextEx() dependency, logic directly implemented +* REVIEWED: GuiScrollBar(), improve mouse-click behaviour +* REVIEWED: Library header info, more info, better organized +* REDESIGNED: GuiTextBox() to support cursor movement +* REDESIGNED: GuiDrawText() to divide drawing by lines +* +* 3.2 (22-May-2022) RENAMED: Some enum values, for unification, avoiding prefixes +* REMOVED: GuiScrollBar(), only internal +* REDESIGNED: GuiPanel() to support text parameter +* REDESIGNED: GuiScrollPanel() to support text parameter +* REDESIGNED: GuiColorPicker() to support text parameter +* REDESIGNED: GuiColorPanel() to support text parameter +* REDESIGNED: GuiColorBarAlpha() to support text parameter +* REDESIGNED: GuiColorBarHue() to support text parameter +* REDESIGNED: GuiTextInputBox() to support password +* +* 3.1 (12-Jan-2022) REVIEWED: Default style for consistency (aligned with rGuiLayout v2.5 tool) +* REVIEWED: GuiLoadStyle() to support compressed font atlas image data and unload previous textures +* REVIEWED: External icons usage logic +* REVIEWED: GuiLine() for centered alignment when including text +* RENAMED: Multiple controls properties definitions to prepend RAYGUI_ +* RENAMED: RICON_ references to RAYGUI_ICON_ for library consistency +* Projects updated and multiple tweaks +* +* 3.0 (04-Nov-2021) Integrated ricons data to avoid external file +* REDESIGNED: GuiTextBoxMulti() +* REMOVED: GuiImageButton*() +* Multiple minor tweaks and bugs corrected +* +* 2.9 (17-Mar-2021) REMOVED: Tooltip API +* 2.8 (03-May-2020) Centralized rectangles drawing to GuiDrawRectangle() +* 2.7 (20-Feb-2020) ADDED: Possible tooltips API +* 2.6 (09-Sep-2019) ADDED: GuiTextInputBox() +* REDESIGNED: GuiListView*(), GuiDropdownBox(), GuiSlider*(), GuiProgressBar(), GuiMessageBox() +* REVIEWED: GuiTextBox(), GuiSpinner(), GuiValueBox(), GuiLoadStyle() +* Replaced property INNER_PADDING by TEXT_PADDING, renamed some properties +* ADDED: 8 new custom styles ready to use +* Multiple minor tweaks and bugs corrected +* +* 2.5 (28-May-2019) Implemented extended GuiTextBox(), GuiValueBox(), GuiSpinner() +* 2.3 (29-Apr-2019) ADDED: rIcons auxiliar library and support for it, multiple controls reviewed +* Refactor all controls drawing mechanism to use control state +* 2.2 (05-Feb-2019) ADDED: GuiScrollBar(), GuiScrollPanel(), reviewed GuiListView(), removed Gui*Ex() controls +* 2.1 (26-Dec-2018) REDESIGNED: GuiCheckBox(), GuiComboBox(), GuiDropdownBox(), GuiToggleGroup() > Use combined text string +* REDESIGNED: Style system (breaking change) +* 2.0 (08-Nov-2018) ADDED: Support controls guiLock and custom fonts +* REVIEWED: GuiComboBox(), GuiListView()... +* 1.9 (09-Oct-2018) REVIEWED: GuiGrid(), GuiTextBox(), GuiTextBoxMulti(), GuiValueBox()... +* 1.8 (01-May-2018) Lot of rework and redesign to align with rGuiStyler and rGuiLayout +* 1.5 (21-Jun-2017) Working in an improved styles system +* 1.4 (15-Jun-2017) Rewritten all GUI functions (removed useless ones) +* 1.3 (12-Jun-2017) Complete redesign of style system +* 1.1 (01-Jun-2017) Complete review of the library +* 1.0 (07-Jun-2016) Converted to header-only by Ramon Santamaria +* 0.9 (07-Mar-2016) Reviewed and tested by Albert Martos, Ian Eito, Sergio Martinez and Ramon Santamaria +* 0.8 (27-Aug-2015) Initial release. Implemented by Kevin Gato, Daniel Nicolás and Ramon Santamaria +* +* DEPENDENCIES: +* raylib 6.1-dev - Inputs reading (keyboard/mouse), shapes drawing, font loading and text drawing +* +* STANDALONE MODE: +* By default raygui depends on raylib mostly for the inputs and the drawing functionality but that dependency can be disabled +* with the config flag RAYGUI_STANDALONE. In that case is up to the user to provide another backend to cover library needs +* +* The following functions should be redefined for a custom backend: +* +* - Vector2 GetMousePosition(void); +* - float GetMouseWheelMove(void); +* - bool IsMouseButtonDown(int button); +* - bool IsMouseButtonPressed(int button); +* - bool IsMouseButtonReleased(int button); +* - bool IsKeyDown(int key); +* - bool IsKeyPressed(int key); +* - int GetCharPressed(void); // -- GuiTextBox(), GuiValueBox() +* +* - void DrawRectangle(int x, int y, int width, int height, Color color); // -- GuiDrawRectangle() +* - void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // -- GuiColorPicker() +* +* - Font GetFontDefault(void); // -- GuiLoadStyleDefault() +* - Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // -- GuiLoadStyle() +* - Texture2D LoadTextureFromImage(Image image); // -- GuiLoadStyle(), required to load texture from embedded font atlas image +* - void SetShapesTexture(Texture2D tex, Rectangle rec); // -- GuiLoadStyle(), required to set shapes rec to font white rec (optimization) +* - char *LoadFileText(const char *fileName); // -- GuiLoadStyle(), required to load charset data +* - void UnloadFileText(char *text); // -- GuiLoadStyle(), required to unload charset data +* - const char *GetDirectoryPath(const char *filePath); // -- GuiLoadStyle(), required to find charset/font file from text .rgs +* - int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle(), required to load required font codepoints list +* - void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list +* - unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle() +* +* CONTRIBUTORS: +* Ramon Santamaria: Supervision, review, redesign, update and maintenance +* Vlad Adrian: Complete rewrite of GuiTextBox() to support extended features (2019) +* Sergio Martinez: Review, testing (2015) and redesign of multiple controls (2018) +* Adria Arranz: Testing and implementation of additional controls (2018) +* Jordi Jorba: Testing and implementation of additional controls (2018) +* Albert Martos: Review and testing of the library (2015) +* Ian Eito: Review and testing of the library (2015) +* Kevin Gato: Initial implementation of basic components (2014) +* Daniel Nicolas: Initial implementation of basic components (2014) +* +* +* LICENSE: zlib/libpng +* +* Copyright (c) 2014-2026 Ramon Santamaria (@raysan5) +* +* This software is provided "as-is", without any express or implied warranty. In no event +* will the authors be held liable for any damages arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, including commercial +* applications, and to alter it and redistribute it freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not claim that you +* wrote the original software. If you use this software in a product, an acknowledgment +* in the product documentation would be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not be misrepresented +* as being the original software. +* +* 3. This notice may not be removed or altered from any source distribution. +* +**********************************************************************************************/ + +#ifndef RAYGUI_H +#define RAYGUI_H + +#define RAYGUI_VERSION_MAJOR 5 +#define RAYGUI_VERSION_MINOR 0 +#define RAYGUI_VERSION_PATCH 0 +#define RAYGUI_VERSION "5.0" + +#if !defined(RAYGUI_STANDALONE) + #include "raylib.h" +#endif + +// Function specifiers in case library is build/used as a shared library (Windows) +// NOTE: Microsoft specifiers to tell compiler that symbols are imported/exported from a .dll +#if defined(_WIN32) + #if defined(BUILD_LIBTYPE_SHARED) + #define RAYGUIAPI __declspec(dllexport) // Building the library as a Win32 shared library (.dll) + #elif defined(USE_LIBTYPE_SHARED) + #define RAYGUIAPI __declspec(dllimport) // Using the library as a Win32 shared library (.dll) + #endif + #if !defined(_CRT_SECURE_NO_WARNINGS) + #define _CRT_SECURE_NO_WARNINGS // Disable unsafe warnings on scanf() functions in MSVC + #endif +#else + #if defined(BUILD_LIBTYPE_SHARED) + #define RAYGUIAPI __attribute__((visibility("default"))) // Building as a Unix shared library (.so/.dylib) + #endif +#endif + +// Function specifiers definition +#ifndef RAYGUIAPI + #define RAYGUIAPI // Functions defined as 'extern' by default (implicit specifiers) +#endif + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +// Simple log system to avoid printf() calls if required +// NOTE: Avoiding those calls, also avoids const strings memory usage +#define RAYGUI_SUPPORT_LOG_INFO +#if defined(RAYGUI_SUPPORT_LOG_INFO) + #define RAYGUI_LOG(...) printf(__VA_ARGS__) +#else + #define RAYGUI_LOG(...) +#endif + +#if !defined(RAYGUI_STANDALONE) +// Macros to define required UI inputs, including mapping to gamepad controls +#if !defined(GUI_BUTTON_DOWN) + #define GUI_BUTTON_DOWN (IsMouseButtonDown(MOUSE_LEFT_BUTTON) || IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) +#endif +#if !defined(GUI_BUTTON_DOWN_ALT) + // Mapping to alternative button down pressed + #define GUI_BUTTON_DOWN_ALT (IsMouseButtonDown(MOUSE_RIGHT_BUTTON) || IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_FACE_RIGHT)) +#endif +#if !defined(GUI_BUTTON_PRESSED) + #define GUI_BUTTON_PRESSED (IsMouseButtonPressed(MOUSE_LEFT_BUTTON) || IsGamepadButtonPressed(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) +#endif +#if !defined(GUI_BUTTON_PRESSED_MID) + #define GUI_BUTTON_PRESSED_MID (IsMouseButtonPressed(MOUSE_MIDDLE_BUTTON) || IsGamepadButtonPressed(0, GAMEPAD_BUTTON_RIGHT_FACE_UP)) +#endif +#if !defined(GUI_BUTTON_RELEASED) + #define GUI_BUTTON_RELEASED (IsMouseButtonReleased(MOUSE_LEFT_BUTTON) || IsGamepadButtonReleased(0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN)) +#endif +#if !defined(GUI_SCROLL_DELTA) + // Mapping to scroll delta changes + // TODO: Review mouse scroll inconsistencies between platforms + #if defined(PLATFORM_WEB) + // NOTE: Gamepad axis triggers not detected on web platform + #define GUI_SCROLL_DELTA ((float)IsGamepadButtonDown(0, GAMEPAD_BUTTON_RIGHT_TRIGGER_2) - (float)IsGamepadButtonDown(0, GAMEPAD_BUTTON_LEFT_TRIGGER_2)) + #else + #define GUI_SCROLL_DELTA (GetMouseWheelMove() + (GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_TRIGGER) + 1) - (GetGamepadAxisMovement(0, GAMEPAD_AXIS_LEFT_TRIGGER) + 1)) + #endif +#endif +#if !defined(GUI_POINTER_POSITION) + #define GUI_POINTER_POSITION GetMousePosition() +#endif +#if !defined(GUI_KEY_DOWN) + #define GUI_KEY_DOWN(key) IsKeyDown(key) +#endif +#if !defined(GUI_KEY_PRESSED) + #define GUI_KEY_PRESSED(key) IsKeyPressed(key) +#endif +#if !defined(GUI_INPUT_KEY) + #define GUI_INPUT_KEY GetCharPressed() +#endif +#else + #define GUI_BUTTON_DOWN 0 + #define GUI_BUTTON_DOWN_ALT 0 + #define GUI_BUTTON_PRESSED 0 + #define GUI_BUTTON_PRESSED_MID 0 + #define GUI_BUTTON_RELEASED 0 + #define GUI_SCROLL_DELTA 0 + #define GUI_POINTER_POSITION (Vector2){ 0 } + #define GUI_KEY_DOWN(key) 0 + #define GUI_KEY_PRESSED(key) 0 + #define GUI_INPUT_KEY 0 +#endif + +//---------------------------------------------------------------------------------- +// Types and Structures Definition +// NOTE: Some types are required for RAYGUI_STANDALONE usage +//---------------------------------------------------------------------------------- +#if defined(RAYGUI_STANDALONE) + #ifndef __cplusplus + // Boolean type + #ifndef true + typedef enum { false, true } bool; + #endif + #endif + + // Vector2 type + typedef struct Vector2 { + float x; + float y; + } Vector2; + + // Vector3 type // -- ConvertHSVtoRGB(), ConvertRGBtoHSV() + typedef struct Vector3 { + float x; + float y; + float z; + } Vector3; + + // Color type, RGBA (32bit) + typedef struct Color { + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a; + } Color; + +#define BLANK (Color){ 0, 0, 0, 0 } // Blank (Transparent) + + // Rectangle type + typedef struct Rectangle { + float x; + float y; + float width; + float height; + } Rectangle; + + // NOTE: Texture2D type is very coupled to raylib, required by Font type + // It should be redesigned to be provided by user + typedef struct Texture { + unsigned int id; // OpenGL texture id + int width; // Texture base width + int height; // Texture base height + int mipmaps; // Mipmap levels, 1 by default + int format; // Data format (PixelFormat type) + } Texture; + + // Texture2D, same as Texture + typedef Texture Texture2D; + + // Image, pixel data stored in CPU memory (RAM) + typedef struct Image { + void *data; // Image raw data + int width; // Image base width + int height; // Image base height + int mipmaps; // Mipmap levels, 1 by default + int format; // Data format (PixelFormat type) + } Image; + + // GlyphInfo, font characters glyphs info + typedef struct GlyphInfo { + int value; // Character value (Unicode) + int offsetX; // Character offset X when drawing + int offsetY; // Character offset Y when drawing + int advanceX; // Character advance position X + Image image; // Character image data + } GlyphInfo; + + // NOTE: Font type is very coupled to raylib, mostly required by GuiLoadStyle() + // It should be redesigned to be provided by user + typedef struct Font { + int baseSize; // Base size (default chars height) + int glyphCount; // Number of glyph characters + int glyphPadding; // Padding around the glyph characters + Texture2D texture; // Texture atlas containing the glyphs + Rectangle *recs; // Rectangles in texture for the glyphs + GlyphInfo *glyphs; // Glyphs info data + } Font; +#endif + +// Style property +// NOTE: Used when exporting style as code for convenience +typedef struct GuiStyleProp { + unsigned short controlId; // Control identifier + unsigned short propertyId; // Property identifier + int propertyValue; // Property value +} GuiStyleProp; + +/* +// Controls text style -NOT USED- +// NOTE: Text style is defined by control +typedef struct GuiTextStyle { + unsigned int size; + int charSpacing; + int lineSpacing; + int alignmentH; + int alignmentV; + int padding; +} GuiTextStyle; +*/ + +// Gui control result +typedef enum { + RESULT_NONE = 0, + RESULT_PRESSED = 1, + RESULT_CHANGED = 2, + + RESULT_TAB_CLOSE = 4 // GuiTabBar(), tab close request +} GuiResult; + +// Gui control state +typedef enum { + STATE_NORMAL = 0, + STATE_FOCUSED, + STATE_PRESSED, + STATE_DISABLED +} GuiState; + +// Gui control text alignment +typedef enum { + TEXT_ALIGN_LEFT = 0, + TEXT_ALIGN_CENTER, + TEXT_ALIGN_RIGHT +} GuiTextAlignment; + +// Gui control text alignment vertical +// NOTE: Text vertical position inside the text bounds +typedef enum { + TEXT_ALIGN_TOP = 0, + TEXT_ALIGN_MIDDLE, + TEXT_ALIGN_BOTTOM +} GuiTextAlignmentVertical; + +// Gui control text wrap mode +// NOTE: Useful for multiline text +typedef enum { + TEXT_WRAP_NONE = 0, + TEXT_WRAP_CHAR, + TEXT_WRAP_WORD +} GuiTextWrapMode; + +// Gui controls +// NOTE: Up to 16 controls supported or 32 controls (v500) +typedef enum { + // Default -> populates to all controls when set + DEFAULT = 0, + + // Basic controls + LABEL = 1, // Used also for: LABELBUTTON + BUTTON = 2, + TOGGLE = 3, // Used also for: TOGGLEGROUP + SLIDER = 4, // Used also for: SLIDERBAR, TOGGLESLIDER + PROGRESSBAR = 5, + CHECKBOX = 6, + COMBOBOX = 7, + DROPDOWNBOX = 8, + TEXTBOX = 9, // Used also for: TEXTBOXMULTI + VALUEBOX = 10, + TABBAR = 11, + LISTVIEW = 12, + COLORPICKER = 13, + SCROLLBAR = 14, + STATUSBAR = 15 + // NOTE: More controls can be added if required +} GuiControl; + +// Controls BASE properties for every control (RAYGUI_MAX_PROPS_BASE = 16) +// NOTE: Properties required for all controls, DEFAULT control sets +// default values for them but they can be overriden per control +typedef enum { + BORDER_COLOR_NORMAL = 0, // Control border color in STATE_NORMAL + BASE_COLOR_NORMAL = 1, // Control base color in STATE_NORMAL + TEXT_COLOR_NORMAL = 2, // Control text color in STATE_NORMAL + BORDER_COLOR_FOCUSED = 3, // Control border color in STATE_FOCUSED + BASE_COLOR_FOCUSED = 4, // Control base color in STATE_FOCUSED + TEXT_COLOR_FOCUSED = 5, // Control text color in STATE_FOCUSED + BORDER_COLOR_PRESSED = 6, // Control border color in STATE_PRESSED + BASE_COLOR_PRESSED = 7, // Control base color in STATE_PRESSED + TEXT_COLOR_PRESSED = 8, // Control text color in STATE_PRESSED + BORDER_COLOR_DISABLED = 9, // Control border color in STATE_DISABLED + BASE_COLOR_DISABLED = 10, // Control base color in STATE_DISABLED + TEXT_COLOR_DISABLED = 11, // Control text color in STATE_DISABLED + BORDER_WIDTH = 12, // Control border size, 0 for no border + TEXT_PADDING = 13, // Control text padding, not considering border + TEXT_ALIGNMENT = 14, // Control text horizontal alignment inside control text bound (after border and padding): 0-Left, 1-Center, 2-Right + BASEPROP16 = 15 // Not used yet... +} GuiControlProperty; + + +// WARNING: Some properties have been chosen to be global with DEFAULT - EXTENDED properties: +// - TEXT_SIZE, // Control text size (glyphs max height) +// - TEXT_SPACING, // Control text spacing between glyphs +// - TEXT_LINE_SPACING, // Control text spacing between lines +// - TEXT_WRAP_MODE // Control text wrap-mode inside text bounds +// +// While other properties can be setup per globally (DEFAULT) or per control: +// - TEXT_PADDING // Control text padding, not considering border +// - TEXT_ALIGNMENT // Control text horizontal alignment inside control text bound + + +// Controls EXTENDED properties (RAYGUI_MAX_PROPS_EXTENDED = 8) +// WARNING: Only 8 slots vailable for those properties per control, including DEFAULT +//---------------------------------------------------------------------------------- +// DEFAULT control, extended properties +// NOTE: Those properties are global for all controls, they can not be setup per control +typedef enum { + TEXT_SIZE = 16, // Text size (glyphs max height) + TEXT_SPACING = 17, // Text spacing between glyphs + LINE_COLOR = 18, // Line control color + BACKGROUND_COLOR = 19, // Background color + TEXT_LINE_SPACING = 20, // Text spacing between lines + TEXT_ALIGNMENT_VERTICAL = 21, // Text vertical alignment inside text bounds (after border and padding): 0-Top, 1-Middle, 2-Bottom + TEXT_WRAP_MODE = 22, // Text wrap-mode inside text bounds + EXTPROP08 = 23 // Not used yet... +} GuiDefaultProperty; + +// Other possible text extended properties: +// TEXT_DECORATION // Text decoration: 0-None, 1-Underline, 2-Line-through, 3-Overline +// TEXT_DECORATION_THICK // Text decoration line thickness +// TEXT_FONT_WEIGHT // Text font weight: 0-Normal, 1-Bold, 2-Italic -> Requires specific font change + +// Label +//typedef enum { } GuiLabelProperty; + +// Button +//typedef enum { } GuiButtonProperty; + +// Toggle/ToggleGroup +typedef enum { + GROUP_PADDING = 16, // ToggleGroup separation between toggles + GROUP_WIDTH_FULL // ToggleGroup bounds width considers all items: 0-Width per item, 1-Full width +} GuiToggleProperty; + +// Slider/SliderBar +typedef enum { + SLIDER_WIDTH = 16, // Slider size of internal bar + SLIDER_PADDING // Slider/SliderBar internal bar padding +} GuiSliderProperty; + +// ProgressBar +typedef enum { + PROGRESS_PADDING = 16, // ProgressBar internal padding + PROGRESS_SIDE, // ProgressBar increment side: 0-Left->Right, 1-Right->Left +} GuiProgressBarProperty; + +// ScrollBar +typedef enum { + ARROWS_SIZE = 16, // ScrollBar arrows size + ARROWS_VISIBLE, // ScrollBar arrows visible + SCROLL_SLIDER_PADDING, // ScrollBar slider internal padding + SCROLL_SLIDER_SIZE, // ScrollBar slider size + SCROLL_PADDING, // ScrollBar scroll padding from arrows + SCROLL_SPEED, // ScrollBar scrolling speed +} GuiScrollBarProperty; + +// CheckBox +typedef enum { + CHECK_PADDING = 16 // CheckBox internal check padding +} GuiCheckBoxProperty; + +// ComboBox +typedef enum { + COMBO_BUTTON_WIDTH = 16, // ComboBox right button width + COMBO_BUTTON_SPACING // ComboBox button separation +} GuiComboBoxProperty; + +// DropdownBox +typedef enum { + ARROW_PADDING = 16, // DropdownBox arrow separation from border and items + DROPDOWN_ITEMS_SPACING, // DropdownBox items separation + DROPDOWN_ARROW_HIDDEN, // DropdownBox arrow hidden + DROPDOWN_ROLL_UP // DropdownBox roll up flag: 0-Roll down, 1-Roll up +} GuiDropdownBoxProperty; + +// TextBox/TextBoxMulti/ValueBox/Spinner +typedef enum { + TEXT_READONLY = 16, // TextBox in read-only mode: 0-Text editable, 1-Text read-only +} GuiTextBoxProperty; + +// ValueBox/Spinner +typedef enum { + SPINNER_BUTTON_WIDTH = 16, // Spinner left/right buttons width + SPINNER_BUTTON_SPACING, // Spinner buttons separation +} GuiValueBoxProperty; + +// TabBar +typedef enum { + TAB_ITEMS_WIDTH = 16, // TabBar tab items width + TAB_CLOSE_BUTTON, // TabBar tab close button: 0-Not shown, 1-Shown + TAB_LINE_SIDE, // TabBar tabs side: 0-Bottom, 1-Top +} GuiTabBarProperty; + +// ListView +#define SCROLLBAR_LEFT_SIDE 0 +#define SCROLLBAR_RIGHT_SIDE 1 + +typedef enum { + LIST_ITEMS_HEIGHT = 16, // ListView items height + LIST_ITEMS_SPACING, // ListView items separation + SCROLLBAR_WIDTH, // ListView scrollbar size (usually width) + SCROLLBAR_SIDE, // ListView scrollbar side: 0-Left side, 1-Right Side + LIST_ITEMS_BORDER_NORMAL, // ListView items border enabled in normal state + LIST_ITEMS_BORDER_WIDTH // ListView items border width +} GuiListViewProperty; + +// ColorPicker +typedef enum { + COLOR_SELECTOR_SIZE = 16, // ColorPicker selector square size + HUEBAR_WIDTH, // ColorPicker right hue bar width + HUEBAR_PADDING, // ColorPicker right hue bar separation from panel + HUEBAR_SELECTOR_HEIGHT, // ColorPicker right hue bar selector height + HUEBAR_SELECTOR_OVERFLOW // ColorPicker right hue bar selector overflow +} GuiColorPickerProperty; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +// ... + +//---------------------------------------------------------------------------------- +// Module Functions Declaration +//---------------------------------------------------------------------------------- + +#if defined(__cplusplus) +extern "C" { // Prevents name mangling of functions +#endif + +// Global gui state control functions +RAYGUIAPI void GuiEnable(void); // Enable gui controls (global state) +RAYGUIAPI void GuiDisable(void); // Disable gui controls (global state) +RAYGUIAPI void GuiLock(void); // Lock gui controls (global state) +RAYGUIAPI void GuiUnlock(void); // Unlock gui controls (global state) +RAYGUIAPI bool GuiIsLocked(void); // Check if gui is locked (global state) +RAYGUIAPI void GuiSetAlpha(float alpha); // Set gui controls alpha (global state), alpha goes from 0.0f to 1.0f +RAYGUIAPI void GuiSetState(int state); // Set gui state (global state) +RAYGUIAPI int GuiGetState(void); // Get gui state (global state) + +// Font set/get functions +RAYGUIAPI void GuiSetFont(Font font); // Set gui custom font (global state) +RAYGUIAPI Font GuiGetFont(void); // Get gui custom font (global state) + +// Style set/get functions +RAYGUIAPI void GuiSetStyle(int control, int property, int value); // Set one style property +RAYGUIAPI int GuiGetStyle(int control, int property); // Get one style property + +// Styles loading functions +RAYGUIAPI void GuiLoadStyle(const char *fileName); // Load style file over global style variable (.rgs) +RAYGUIAPI void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize); // Load style from memory (binary only) +RAYGUIAPI void GuiLoadStyleDefault(void); // Load style default over global style + +// Tooltips management functions +RAYGUIAPI void GuiEnableTooltip(void); // Enable gui tooltips (global state) +RAYGUIAPI void GuiDisableTooltip(void); // Disable gui tooltips (global state) +RAYGUIAPI void GuiSetTooltip(const char *tooltip); // Set tooltip string + +// Icons functionality +RAYGUIAPI const char *GuiIconText(int iconId, const char *text); // Get text with icon id prepended (if supported) +#if !defined(RAYGUI_NO_ICONS) +RAYGUIAPI void GuiSetIconScale(int scale); // Set default icon drawing size +RAYGUIAPI unsigned int *GuiGetIcons(void); // Get raygui icons data pointer +RAYGUIAPI char **GuiLoadIcons(const char *fileName, bool loadIconsName); // Load raygui icons file (.rgi) into internal icons data +RAYGUIAPI char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName); // Load raygui icons file (.rgi) from memory into internal icons data +RAYGUIAPI void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color); // Draw icon using pixel size at specified position +#endif + +// Utility functions +RAYGUIAPI int GuiGetTextWidth(const char *text); // Get text width considering gui style and icon size (if required) + +// Controls +//---------------------------------------------------------------------------------------------------------- +// Container/separator controls, useful for controls organization +RAYGUIAPI int GuiWindowBox(Rectangle bounds, const char *title); // Window Box control, shows a window that can be closed +RAYGUIAPI int GuiGroupBox(Rectangle bounds, const char *text); // Group Box control with text name +RAYGUIAPI int GuiLine(Rectangle bounds, const char *text); // Line separator control, could contain text +RAYGUIAPI int GuiPanel(Rectangle bounds, const char *text); // Panel control, useful to group controls +RAYGUIAPI int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view); // Scroll Panel control + +// Basic controls set +RAYGUIAPI int GuiLabel(Rectangle bounds, const char *text); // Label control +RAYGUIAPI int GuiButton(Rectangle bounds, const char *text); // Button control, returns true when clicked +RAYGUIAPI int GuiLabelButton(Rectangle bounds, const char *text); // Label button control, returns true when clicked +RAYGUIAPI int GuiToggle(Rectangle bounds, const char *text, bool *active); // Toggle Button control +RAYGUIAPI int GuiToggleGroup(Rectangle bounds, const char *text, int *active); // Toggle Group control +RAYGUIAPI int GuiToggleSlider(Rectangle bounds, const char *text, int *active); // Toggle Slider control +RAYGUIAPI int GuiCheckBox(Rectangle bounds, const char *text, bool *checked); // Check Box control, returns true when active +RAYGUIAPI int GuiComboBox(Rectangle bounds, const char *text, int *active); // Combo Box control + +RAYGUIAPI int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode); // Dropdown Box control +RAYGUIAPI int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Spinner control +RAYGUIAPI int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode); // Value Box control, updates input text with numbers +RAYGUIAPI int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode); // Value box control for float values +RAYGUIAPI int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode); // Text Box control, updates input text + +RAYGUIAPI int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider control +RAYGUIAPI int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Slider Bar control +RAYGUIAPI int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue); // Progress Bar control +RAYGUIAPI int GuiStatusBar(Rectangle bounds, const char *text); // Status Bar control, shows info text +RAYGUIAPI int GuiDummyRec(Rectangle bounds, const char *text); // Dummy control for placeholders +RAYGUIAPI int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vector2 *mouseCell); // Grid control + +// Advance controls set +RAYGUIAPI int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active); // List View control +RAYGUIAPI int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus); // List View control, using text entries list and returning focus entry +RAYGUIAPI int GuiTabBar(Rectangle bounds, const char *text, int *hscroll, int *active); // Tab Bar control +RAYGUIAPI int GuiTabBarEx(Rectangle bounds, char **text, int count, int *hscroll, int *active, int *focus); // Tab Bar control, using text entries list and returning focus entry +RAYGUIAPI int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *btnText, int *btnActive); // Message Box control, displays a message +RAYGUIAPI int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, char *text, int textSize, const char *btnText, int *btnActive, bool *secretViewActive); // Text Input Box control, ask for text, supports secret +RAYGUIAPI int GuiColorPicker(Rectangle bounds, const char *text, Color *color); // Color Picker control, includes Color bar controls +RAYGUIAPI int GuiColorPanel(Rectangle bounds, const char *text, Color *color); // Color Panel control +RAYGUIAPI int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha); // Color Bar Alpha control +RAYGUIAPI int GuiColorBarHue(Rectangle bounds, const char *text, float *value); // Color Bar Hue control +RAYGUIAPI int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Picker control, using Hue-Saturation-Value color data, includes Color bar controls +RAYGUIAPI int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv); // Color Panel control, using Hue-Saturation-Value color data +//---------------------------------------------------------------------------------------------------------- + +#if !defined(RAYGUI_NO_ICONS) + +#if !defined(RAYGUI_CUSTOM_ICONS) +//---------------------------------------------------------------------------------- +// Icons enumeration +//---------------------------------------------------------------------------------- +typedef enum { + ICON_NONE = 0, + ICON_FOLDER_FILE_OPEN = 1, + ICON_FILE_SAVE_CLASSIC = 2, + ICON_FOLDER_OPEN = 3, + ICON_FOLDER_SAVE = 4, + ICON_FILE_OPEN = 5, + ICON_FILE_SAVE = 6, + ICON_FILE_EXPORT = 7, + ICON_FILE_ADD = 8, + ICON_FILE_DELETE = 9, + ICON_FILETYPE_TEXT = 10, + ICON_FILETYPE_AUDIO = 11, + ICON_FILETYPE_IMAGE = 12, + ICON_FILETYPE_PLAY = 13, + ICON_FILETYPE_VIDEO = 14, + ICON_FILETYPE_INFO = 15, + ICON_FILE_COPY = 16, + ICON_FILE_CUT = 17, + ICON_FILE_PASTE = 18, + ICON_CURSOR_HAND = 19, + ICON_CURSOR_POINTER = 20, + ICON_CURSOR_CLASSIC = 21, + ICON_PENCIL = 22, + ICON_PENCIL_BIG = 23, + ICON_BRUSH_CLASSIC = 24, + ICON_BRUSH_PAINTER = 25, + ICON_WATER_DROP = 26, + ICON_COLOR_PICKER = 27, + ICON_RUBBER = 28, + ICON_COLOR_BUCKET = 29, + ICON_TEXT_T = 30, + ICON_TEXT_A = 31, + ICON_SCALE = 32, + ICON_RESIZE = 33, + ICON_FILTER_POINT = 34, + ICON_FILTER_BILINEAR = 35, + ICON_CROP = 36, + ICON_CROP_ALPHA = 37, + ICON_SQUARE_TOGGLE = 38, + ICON_SYMMETRY = 39, + ICON_SYMMETRY_HORIZONTAL = 40, + ICON_SYMMETRY_VERTICAL = 41, + ICON_LENS = 42, + ICON_LENS_BIG = 43, + ICON_EYE_ON = 44, + ICON_EYE_OFF = 45, + ICON_FILTER_TOP = 46, + ICON_FILTER = 47, + ICON_TARGET_POINT = 48, + ICON_TARGET_SMALL = 49, + ICON_TARGET_BIG = 50, + ICON_TARGET_MOVE = 51, + ICON_CURSOR_MOVE = 52, + ICON_CURSOR_SCALE = 53, + ICON_CURSOR_SCALE_RIGHT = 54, + ICON_CURSOR_SCALE_LEFT = 55, + ICON_UNDO = 56, + ICON_REDO = 57, + ICON_REREDO = 58, + ICON_MUTATE = 59, + ICON_ROTATE = 60, + ICON_REPEAT = 61, + ICON_SHUFFLE = 62, + ICON_EMPTYBOX = 63, + ICON_TARGET = 64, + ICON_TARGET_SMALL_FILL = 65, + ICON_TARGET_BIG_FILL = 66, + ICON_TARGET_MOVE_FILL = 67, + ICON_CURSOR_MOVE_FILL = 68, + ICON_CURSOR_SCALE_FILL = 69, + ICON_CURSOR_SCALE_RIGHT_FILL = 70, + ICON_CURSOR_SCALE_LEFT_FILL = 71, + ICON_UNDO_FILL = 72, + ICON_REDO_FILL = 73, + ICON_REREDO_FILL = 74, + ICON_MUTATE_FILL = 75, + ICON_ROTATE_FILL = 76, + ICON_REPEAT_FILL = 77, + ICON_SHUFFLE_FILL = 78, + ICON_EMPTYBOX_SMALL = 79, + ICON_BOX = 80, + ICON_BOX_TOP = 81, + ICON_BOX_TOP_RIGHT = 82, + ICON_BOX_RIGHT = 83, + ICON_BOX_BOTTOM_RIGHT = 84, + ICON_BOX_BOTTOM = 85, + ICON_BOX_BOTTOM_LEFT = 86, + ICON_BOX_LEFT = 87, + ICON_BOX_TOP_LEFT = 88, + ICON_BOX_CENTER = 89, + ICON_BOX_CIRCLE_MASK = 90, + ICON_POT = 91, + ICON_ALPHA_MULTIPLY = 92, + ICON_ALPHA_CLEAR = 93, + ICON_DITHERING = 94, + ICON_MIPMAPS = 95, + ICON_BOX_GRID = 96, + ICON_GRID = 97, + ICON_BOX_CORNERS_SMALL = 98, + ICON_BOX_CORNERS_BIG = 99, + ICON_FOUR_BOXES = 100, + ICON_GRID_FILL = 101, + ICON_BOX_MULTISIZE = 102, + ICON_ZOOM_SMALL = 103, + ICON_ZOOM_MEDIUM = 104, + ICON_ZOOM_BIG = 105, + ICON_ZOOM_ALL = 106, + ICON_ZOOM_CENTER = 107, + ICON_BOX_DOTS_SMALL = 108, + ICON_BOX_DOTS_BIG = 109, + ICON_BOX_CONCENTRIC = 110, + ICON_BOX_GRID_BIG = 111, + ICON_OK_TICK = 112, + ICON_CROSS = 113, + ICON_ARROW_LEFT = 114, + ICON_ARROW_RIGHT = 115, + ICON_ARROW_DOWN = 116, + ICON_ARROW_UP = 117, + ICON_ARROW_LEFT_FILL = 118, + ICON_ARROW_RIGHT_FILL = 119, + ICON_ARROW_DOWN_FILL = 120, + ICON_ARROW_UP_FILL = 121, + ICON_AUDIO = 122, + ICON_FX = 123, + ICON_WAVE = 124, + ICON_WAVE_SINUS = 125, + ICON_WAVE_SQUARE = 126, + ICON_WAVE_TRIANGULAR = 127, + ICON_CROSS_SMALL = 128, + ICON_PLAYER_PREVIOUS = 129, + ICON_PLAYER_PLAY_BACK = 130, + ICON_PLAYER_PLAY = 131, + ICON_PLAYER_PAUSE = 132, + ICON_PLAYER_STOP = 133, + ICON_PLAYER_NEXT = 134, + ICON_PLAYER_RECORD = 135, + ICON_MAGNET = 136, + ICON_LOCK_CLOSE = 137, + ICON_LOCK_OPEN = 138, + ICON_CLOCK = 139, + ICON_TOOLS = 140, + ICON_GEAR = 141, + ICON_GEAR_BIG = 142, + ICON_BIN = 143, + ICON_HAND_POINTER = 144, + ICON_LASER = 145, + ICON_COIN = 146, + ICON_EXPLOSION = 147, + ICON_1UP = 148, + ICON_PLAYER = 149, + ICON_PLAYER_JUMP = 150, + ICON_KEY = 151, + ICON_DEMON = 152, + ICON_TEXT_POPUP = 153, + ICON_GEAR_EX = 154, + ICON_CRACK = 155, + ICON_CRACK_POINTS = 156, + ICON_STAR = 157, + ICON_DOOR = 158, + ICON_EXIT = 159, + ICON_MODE_2D = 160, + ICON_MODE_3D = 161, + ICON_CUBE = 162, + ICON_CUBE_FACE_TOP = 163, + ICON_CUBE_FACE_LEFT = 164, + ICON_CUBE_FACE_FRONT = 165, + ICON_CUBE_FACE_BOTTOM = 166, + ICON_CUBE_FACE_RIGHT = 167, + ICON_CUBE_FACE_BACK = 168, + ICON_CAMERA = 169, + ICON_SPECIAL = 170, + ICON_LINK_NET = 171, + ICON_LINK_BOXES = 172, + ICON_LINK_MULTI = 173, + ICON_LINK = 174, + ICON_LINK_BROKE = 175, + ICON_TEXT_NOTES = 176, + ICON_NOTEBOOK = 177, + ICON_SUITCASE = 178, + ICON_SUITCASE_ZIP = 179, + ICON_MAILBOX = 180, + ICON_MONITOR = 181, + ICON_PRINTER = 182, + ICON_PHOTO_CAMERA = 183, + ICON_PHOTO_CAMERA_FLASH = 184, + ICON_HOUSE = 185, + ICON_HEART = 186, + ICON_CORNER = 187, + ICON_VERTICAL_BARS = 188, + ICON_VERTICAL_BARS_FILL = 189, + ICON_LIFE_BARS = 190, + ICON_INFO = 191, + ICON_CROSSLINE = 192, + ICON_HELP = 193, + ICON_FILETYPE_ALPHA = 194, + ICON_FILETYPE_HOME = 195, + ICON_LAYERS_VISIBLE = 196, + ICON_LAYERS = 197, + ICON_WINDOW = 198, + ICON_HIDPI = 199, + ICON_FILETYPE_BINARY = 200, + ICON_HEX = 201, + ICON_SHIELD = 202, + ICON_FILE_NEW = 203, + ICON_FOLDER_ADD = 204, + ICON_ALARM = 205, + ICON_CPU = 206, + ICON_ROM = 207, + ICON_STEP_OVER = 208, + ICON_STEP_INTO = 209, + ICON_STEP_OUT = 210, + ICON_RESTART = 211, + ICON_BREAKPOINT_ON = 212, + ICON_BREAKPOINT_OFF = 213, + ICON_BURGER_MENU = 214, + ICON_CASE_SENSITIVE = 215, + ICON_REG_EXP = 216, + ICON_FOLDER = 217, + ICON_FILE = 218, + ICON_SAND_TIMER = 219, + ICON_WARNING = 220, + ICON_HELP_BOX = 221, + ICON_INFO_BOX = 222, + ICON_PRIORITY = 223, + ICON_LAYERS_ISO = 224, + ICON_LAYERS2 = 225, + ICON_MLAYERS = 226, + ICON_MAPS = 227, + ICON_HOT = 228, + ICON_LABEL = 229, + ICON_NAME_ID = 230, + ICON_SLICING = 231, + ICON_MANUAL_CONTROL = 232, + ICON_COLLISION = 233, + ICON_CIRCLE_ADD = 234, + ICON_CIRCLE_ADD_FILL = 235, + ICON_CIRCLE_WARNING = 236, + ICON_CIRCLE_WARNING_FILL = 237, + ICON_BOX_MORE = 238, + ICON_BOX_MORE_FILL = 239, + ICON_BOX_MINUS = 240, + ICON_BOX_MINUS_FILL = 241, + ICON_UNION = 242, + ICON_INTERSECTION = 243, + ICON_DIFFERENCE = 244, + ICON_SPHERE = 245, + ICON_CYLINDER = 246, + ICON_CONE = 247, + ICON_ELLIPSOID = 248, + ICON_CAPSULE = 249, + ICON_FILETYPE_FONT = 250, + ICON_FILETYPE_3D = 251, + ICON_FILETYPE_CODE_XML = 252, + ICON_FILETYPE_CODE_C = 253, + ICON_FILETYPE_CODE_PYTHON = 254, + ICON_FILETYPE_CODE_JS = 255, + ICON_FILETYPE_ICON = 256, +} GuiIconName; +#endif + +#endif // RAYGUI_NO_ICONS + +#if defined(__cplusplus) +} // Prevents name mangling of functions +#endif + +#endif // RAYGUI_H + +/*********************************************************************************** +* +* RAYGUI IMPLEMENTATION +* +************************************************************************************/ + +#if defined(RAYGUI_IMPLEMENTATION) + +#include // Required for: FILE, fopen(), fclose(), fprintf(), feof(), fscanf(), snprintf(), vsprintf() [GuiLoadStyle(), GuiLoadIcons()] +#include // Required for: strlen() [GuiTextBox(), GuiValueBox()], memset(), memcpy() +#include // Required for: va_list, va_start(), vfprintf(), va_end() [TextFormat()] +#include // Required for: roundf() [GuiColorPicker()] +#include // Required for: isspace() [GuiTextBox()] + +// Allow custom memory allocators +#if defined(RAYGUI_MALLOC) || defined(RAYGUI_CALLOC) || defined(RAYGUI_FREE) + #if !defined(RAYGUI_MALLOC) || !defined(RAYGUI_CALLOC) || !defined(RAYGUI_FREE) + #error "RAYGUI: if RAYGUI_MALLOC, RAYGUI_CALLOC, or RAYGUI_FREE is customized, all three must be customized" + #endif +#else + #include // Required for: malloc(), calloc(), free() [GuiLoadStyle(), GuiLoadIcons()] + + #define RAYGUI_MALLOC(sz) malloc(sz) + #define RAYGUI_CALLOC(n,sz) calloc(n,sz) + #define RAYGUI_FREE(p) free(p) +#endif + +#ifdef __cplusplus + #define RAYGUI_CLITERAL(name) name +#else + #define RAYGUI_CLITERAL(name) (name) +#endif + +// Check if two rectangles are equal, used to validate a slider bounds as an id +#ifndef CHECK_BOUNDS_ID + #define CHECK_BOUNDS_ID(src, dst) (((int)src.x == (int)dst.x) && ((int)src.y == (int)dst.y) && ((int)src.width == (int)dst.width) && ((int)src.height == (int)dst.height)) +#endif + +#if !defined(RAYGUI_NO_ICONS) && !defined(RAYGUI_CUSTOM_ICONS) + +// Embedded icons, no external file provided +#define RAYGUI_ICON_SIZE 16 // Size of icons in pixels (squared) +#define RAYGUI_ICON_MAX_ICONS 512 // Maximum number of icons +#define RAYGUI_ICON_MAX_FONT_BACKED 257 // Maximum number of icons to back in font atlas +#define RAYGUI_ICON_MAX_NAME_LENGTH 32 // Maximum length of icon name id +#define RAYGUI_ICON_FONT_ATLAS_PADDING 1 // Padding between backed icons in font atlas + +// Icons data is defined by bit array (every bit represents one pixel) +// Those arrays are stored as unsigned int data arrays, so, +// every array element defines 32 pixels (bits) of information +// One icon is defined by 8 int, (8 int*32 bit = 256 bit = 16*16 pixels) +// NOTE: Number of elemens depend on RAYGUI_ICON_SIZE (by default 16x16 pixels) +#define RAYGUI_ICON_DATA_ELEMENTS (RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32) + +//---------------------------------------------------------------------------------- +// Icons data for all gui possible icons (allocated on data segment by default) +// +// NOTE 1: Every icon is codified in binary form, using 1 bit per pixel, so, +// every 16x16 icon requires 8 integers (16*16/32) to be stored +// +// NOTE 2: A different icon set could be loaded over this array using GuiLoadIcons(), +// but loaded icons set must be same RAYGUI_ICON_SIZE and no more than RAYGUI_ICON_MAX_ICONS +// +// guiIcons size is by default: 512*(16*16/32) = 16384 bytes = 16 KB +//---------------------------------------------------------------------------------- +static unsigned int guiIcons[RAYGUI_ICON_MAX_ICONS*RAYGUI_ICON_DATA_ELEMENTS] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_NONE + 0x3ff80000, 0x2f082008, 0x2042207e, 0x40027fc2, 0x40024002, 0x40024002, 0x40024002, 0x00007ffe, // ICON_FOLDER_FILE_OPEN + 0x3ffe0000, 0x44226422, 0x400247e2, 0x5ffa4002, 0x57ea500a, 0x500a500a, 0x40025ffa, 0x00007ffe, // ICON_FILE_SAVE_CLASSIC + 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024002, 0x44424282, 0x793e4102, 0x00000100, // ICON_FOLDER_OPEN + 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x41024102, 0x44424102, 0x793e4282, 0x00000000, // ICON_FOLDER_SAVE + 0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x24442284, 0x21042104, 0x20042104, 0x00003ffc, // ICON_FILE_OPEN + 0x3ff00000, 0x201c2010, 0x20042004, 0x21042004, 0x21042104, 0x22842444, 0x20042104, 0x00003ffc, // ICON_FILE_SAVE + 0x3ff00000, 0x201c2010, 0x00042004, 0x20041004, 0x20844784, 0x00841384, 0x20042784, 0x00003ffc, // ICON_FILE_EXPORT + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x22042204, 0x22042f84, 0x20042204, 0x00003ffc, // ICON_FILE_ADD + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x25042884, 0x25042204, 0x20042884, 0x00003ffc, // ICON_FILE_DELETE + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // ICON_FILETYPE_TEXT + 0x3ff00000, 0x201c2010, 0x27042004, 0x244424c4, 0x26442444, 0x20642664, 0x20042004, 0x00003ffc, // ICON_FILETYPE_AUDIO + 0x3ff00000, 0x201c2010, 0x26042604, 0x20042004, 0x35442884, 0x2414222c, 0x20042004, 0x00003ffc, // ICON_FILETYPE_IMAGE + 0x3ff00000, 0x201c2010, 0x20c42004, 0x22442144, 0x22442444, 0x20c42144, 0x20042004, 0x00003ffc, // ICON_FILETYPE_PLAY + 0x3ff00000, 0x3ffc2ff0, 0x3f3c2ff4, 0x3dbc2eb4, 0x3dbc2bb4, 0x3f3c2eb4, 0x3ffc2ff4, 0x00002ff4, // ICON_FILETYPE_VIDEO + 0x3ff00000, 0x201c2010, 0x21842184, 0x21842004, 0x21842184, 0x21842184, 0x20042184, 0x00003ffc, // ICON_FILETYPE_INFO + 0x0ff00000, 0x381c0810, 0x28042804, 0x28042804, 0x28042804, 0x28042804, 0x20102ffc, 0x00003ff0, // ICON_FILE_COPY + 0x00000000, 0x701c0000, 0x079c1e14, 0x55a000f0, 0x079c00f0, 0x701c1e14, 0x00000000, 0x00000000, // ICON_FILE_CUT + 0x01c00000, 0x13e41bec, 0x3f841004, 0x204420c4, 0x20442044, 0x20442044, 0x207c2044, 0x00003fc0, // ICON_FILE_PASTE + 0x00000000, 0x3aa00fe0, 0x2abc2aa0, 0x2aa42aa4, 0x20042aa4, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_CURSOR_HAND + 0x00000000, 0x003c000c, 0x030800c8, 0x30100c10, 0x10202020, 0x04400840, 0x01800280, 0x00000000, // ICON_CURSOR_POINTER + 0x00000000, 0x00180000, 0x01f00078, 0x03e007f0, 0x07c003e0, 0x04000e40, 0x00000000, 0x00000000, // ICON_CURSOR_CLASSIC + 0x00000000, 0x04000000, 0x11000a00, 0x04400a80, 0x01100220, 0x00580088, 0x00000038, 0x00000000, // ICON_PENCIL + 0x04000000, 0x15000a00, 0x50402880, 0x14102820, 0x05040a08, 0x015c028c, 0x007c00bc, 0x00000000, // ICON_PENCIL_BIG + 0x01c00000, 0x01400140, 0x01400140, 0x0ff80140, 0x0ff80808, 0x0aa80808, 0x0aa80aa8, 0x00000ff8, // ICON_BRUSH_CLASSIC + 0x1ffc0000, 0x5ffc7ffe, 0x40004000, 0x00807f80, 0x01c001c0, 0x01c001c0, 0x01c001c0, 0x00000080, // ICON_BRUSH_PAINTER + 0x00000000, 0x00800000, 0x01c00080, 0x03e001c0, 0x07f003e0, 0x036006f0, 0x000001c0, 0x00000000, // ICON_WATER_DROP + 0x00000000, 0x3e003800, 0x1f803f80, 0x0c201e40, 0x02080c10, 0x00840104, 0x00380044, 0x00000000, // ICON_COLOR_PICKER + 0x00000000, 0x07800300, 0x1fe00fc0, 0x3f883fd0, 0x0e021f04, 0x02040402, 0x00f00108, 0x00000000, // ICON_RUBBER + 0x00c00000, 0x02800140, 0x08200440, 0x20081010, 0x2ffe3004, 0x03f807fc, 0x00e001f0, 0x00000040, // ICON_COLOR_BUCKET + 0x00000000, 0x21843ffc, 0x01800180, 0x01800180, 0x01800180, 0x01800180, 0x03c00180, 0x00000000, // ICON_TEXT_T + 0x00800000, 0x01400180, 0x06200340, 0x0c100620, 0x1ff80c10, 0x380c1808, 0x70067004, 0x0000f80f, // ICON_TEXT_A + 0x78000000, 0x50004000, 0x00004800, 0x03c003c0, 0x03c003c0, 0x00100000, 0x0002000a, 0x0000000e, // ICON_SCALE + 0x75560000, 0x5e004002, 0x54001002, 0x41001202, 0x408200fe, 0x40820082, 0x40820082, 0x00006afe, // ICON_RESIZE + 0x00000000, 0x3f003f00, 0x3f003f00, 0x3f003f00, 0x00400080, 0x001c0020, 0x001c001c, 0x00000000, // ICON_FILTER_POINT + 0x6d800000, 0x00004080, 0x40804080, 0x40800000, 0x00406d80, 0x001c0020, 0x001c001c, 0x00000000, // ICON_FILTER_BILINEAR + 0x40080000, 0x1ffe2008, 0x14081008, 0x11081208, 0x10481088, 0x10081028, 0x10047ff8, 0x00001002, // ICON_CROP + 0x00100000, 0x3ffc0010, 0x2ab03550, 0x22b02550, 0x20b02150, 0x20302050, 0x2000fff0, 0x00002000, // ICON_CROP_ALPHA + 0x40000000, 0x1ff82000, 0x04082808, 0x01082208, 0x00482088, 0x00182028, 0x35542008, 0x00000002, // ICON_SQUARE_TOGGLE + 0x00000000, 0x02800280, 0x06c006c0, 0x0ea00ee0, 0x1e901eb0, 0x3e883e98, 0x7efc7e8c, 0x00000000, // ICON_SYMMETRY + 0x01000000, 0x05600100, 0x1d480d50, 0x7d423d44, 0x3d447d42, 0x0d501d48, 0x01000560, 0x00000100, // ICON_SYMMETRY_HORIZONTAL + 0x01800000, 0x04200240, 0x10080810, 0x00001ff8, 0x00007ffe, 0x0ff01ff8, 0x03c007e0, 0x00000180, // ICON_SYMMETRY_VERTICAL + 0x00000000, 0x010800f0, 0x02040204, 0x02040204, 0x07f00308, 0x1c000e00, 0x30003800, 0x00000000, // ICON_LENS + 0x00000000, 0x061803f0, 0x08240c0c, 0x08040814, 0x0c0c0804, 0x23f01618, 0x18002400, 0x00000000, // ICON_LENS_BIG + 0x00000000, 0x00000000, 0x1c7007c0, 0x638e3398, 0x1c703398, 0x000007c0, 0x00000000, 0x00000000, // ICON_EYE_ON + 0x00000000, 0x10002000, 0x04700fc0, 0x610e3218, 0x1c703098, 0x001007a0, 0x00000008, 0x00000000, // ICON_EYE_OFF + 0x00000000, 0x00007ffc, 0x40047ffc, 0x10102008, 0x04400820, 0x02800280, 0x02800280, 0x00000100, // ICON_FILTER_TOP + 0x00000000, 0x40027ffe, 0x10082004, 0x04200810, 0x02400240, 0x02400240, 0x01400240, 0x000000c0, // ICON_FILTER + 0x00800000, 0x00800080, 0x00000080, 0x3c9e0000, 0x00000000, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_POINT + 0x00800000, 0x00800080, 0x00800080, 0x3f7e01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_SMALL + 0x00800000, 0x00800080, 0x03e00080, 0x3e3e0220, 0x03e00220, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_BIG + 0x01000000, 0x04400280, 0x01000100, 0x43842008, 0x43849ab2, 0x01002008, 0x04400100, 0x01000280, // ICON_TARGET_MOVE + 0x01000000, 0x04400280, 0x01000100, 0x41042108, 0x41049ff2, 0x01002108, 0x04400100, 0x01000280, // ICON_CURSOR_MOVE + 0x781e0000, 0x500a4002, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x4002500a, 0x0000781e, // ICON_CURSOR_SCALE + 0x00000000, 0x20003c00, 0x24002800, 0x01000200, 0x00400080, 0x00140024, 0x003c0004, 0x00000000, // ICON_CURSOR_SCALE_RIGHT + 0x00000000, 0x0004003c, 0x00240014, 0x00800040, 0x02000100, 0x28002400, 0x3c002000, 0x00000000, // ICON_CURSOR_SCALE_LEFT + 0x00000000, 0x00100020, 0x10101fc8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // ICON_UNDO + 0x00000000, 0x08000400, 0x080813f8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // ICON_REDO + 0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3f902020, 0x00400020, 0x00000000, // ICON_REREDO + 0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3fc82010, 0x00200010, 0x00000000, // ICON_MUTATE + 0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18101020, 0x00100fc8, 0x00000020, // ICON_ROTATE + 0x00000000, 0x04000200, 0x240429fc, 0x20042204, 0x20442004, 0x3f942024, 0x00400020, 0x00000000, // ICON_REPEAT + 0x00000000, 0x20001000, 0x22104c0e, 0x00801120, 0x11200040, 0x4c0e2210, 0x10002000, 0x00000000, // ICON_SHUFFLE + 0x7ffe0000, 0x50024002, 0x44024802, 0x41024202, 0x40424082, 0x40124022, 0x4002400a, 0x00007ffe, // ICON_EMPTYBOX + 0x00800000, 0x03e00080, 0x08080490, 0x3c9e0808, 0x08080808, 0x03e00490, 0x00800080, 0x00000000, // ICON_TARGET + 0x00800000, 0x00800080, 0x00800080, 0x3ffe01c0, 0x008001c0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_SMALL_FILL + 0x00800000, 0x00800080, 0x03e00080, 0x3ffe03e0, 0x03e003e0, 0x00800080, 0x00800080, 0x00000000, // ICON_TARGET_BIG_FILL + 0x01000000, 0x07c00380, 0x01000100, 0x638c2008, 0x638cfbbe, 0x01002008, 0x07c00100, 0x01000380, // ICON_TARGET_MOVE_FILL + 0x01000000, 0x07c00380, 0x01000100, 0x610c2108, 0x610cfffe, 0x01002108, 0x07c00100, 0x01000380, // ICON_CURSOR_MOVE_FILL + 0x781e0000, 0x6006700e, 0x04204812, 0x00000240, 0x02400000, 0x48120420, 0x700e6006, 0x0000781e, // ICON_CURSOR_SCALE_FILL + 0x00000000, 0x38003c00, 0x24003000, 0x01000200, 0x00400080, 0x000c0024, 0x003c001c, 0x00000000, // ICON_CURSOR_SCALE_RIGHT_FILL + 0x00000000, 0x001c003c, 0x0024000c, 0x00800040, 0x02000100, 0x30002400, 0x3c003800, 0x00000000, // ICON_CURSOR_SCALE_LEFT_FILL + 0x00000000, 0x00300020, 0x10301ff8, 0x10001020, 0x10001000, 0x10001000, 0x00001fc0, 0x00000000, // ICON_UNDO_FILL + 0x00000000, 0x0c000400, 0x0c081ff8, 0x00080408, 0x00080008, 0x00080008, 0x000003f8, 0x00000000, // ICON_REDO_FILL + 0x00000000, 0x3ffc0000, 0x20042004, 0x20002000, 0x20402000, 0x3ff02060, 0x00400060, 0x00000000, // ICON_REREDO_FILL + 0x00000000, 0x3ffc0000, 0x20042004, 0x27fc2004, 0x20202000, 0x3ff82030, 0x00200030, 0x00000000, // ICON_MUTATE_FILL + 0x00000000, 0x0ff00000, 0x10081818, 0x11801008, 0x10001180, 0x18301020, 0x00300ff8, 0x00000020, // ICON_ROTATE_FILL + 0x00000000, 0x06000200, 0x26042ffc, 0x20042204, 0x20442004, 0x3ff42064, 0x00400060, 0x00000000, // ICON_REPEAT_FILL + 0x00000000, 0x30001000, 0x32107c0e, 0x00801120, 0x11200040, 0x7c0e3210, 0x10003000, 0x00000000, // ICON_SHUFFLE_FILL + 0x00000000, 0x30043ffc, 0x24042804, 0x21042204, 0x20442084, 0x20142024, 0x3ffc200c, 0x00000000, // ICON_EMPTYBOX_SMALL + 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX + 0x00000000, 0x23c43ffc, 0x23c423c4, 0x200423c4, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP + 0x00000000, 0x3e043ffc, 0x3e043e04, 0x20043e04, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP_RIGHT + 0x00000000, 0x20043ffc, 0x20042004, 0x3e043e04, 0x3e043e04, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_RIGHT + 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x3e042004, 0x3e043e04, 0x3ffc3e04, 0x00000000, // ICON_BOX_BOTTOM_RIGHT + 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x23c42004, 0x23c423c4, 0x3ffc23c4, 0x00000000, // ICON_BOX_BOTTOM + 0x00000000, 0x20043ffc, 0x20042004, 0x20042004, 0x207c2004, 0x207c207c, 0x3ffc207c, 0x00000000, // ICON_BOX_BOTTOM_LEFT + 0x00000000, 0x20043ffc, 0x20042004, 0x207c207c, 0x207c207c, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_LEFT + 0x00000000, 0x207c3ffc, 0x207c207c, 0x2004207c, 0x20042004, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_TOP_LEFT + 0x00000000, 0x20043ffc, 0x20042004, 0x23c423c4, 0x23c423c4, 0x20042004, 0x3ffc2004, 0x00000000, // ICON_BOX_CENTER + 0x7ffe0000, 0x40024002, 0x47e24182, 0x4ff247e2, 0x47e24ff2, 0x418247e2, 0x40024002, 0x00007ffe, // ICON_BOX_CIRCLE_MASK + 0x7fff0000, 0x40014001, 0x40014001, 0x49555ddd, 0x4945495d, 0x400149c5, 0x40014001, 0x00007fff, // ICON_POT + 0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x404e40ce, 0x48125432, 0x4006540e, 0x00007ffe, // ICON_ALPHA_MULTIPLY + 0x7ffe0000, 0x53327332, 0x44ce4cce, 0x41324332, 0x5c4e40ce, 0x44124432, 0x40065c0e, 0x00007ffe, // ICON_ALPHA_CLEAR + 0x7ffe0000, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x42fe417e, 0x00007ffe, // ICON_DITHERING + 0x07fe0000, 0x1ffa0002, 0x7fea000a, 0x402a402a, 0x5b2a512a, 0x5128552a, 0x40205128, 0x00007fe0, // ICON_MIPMAPS + 0x00000000, 0x1ff80000, 0x12481248, 0x12481ff8, 0x1ff81248, 0x12481248, 0x00001ff8, 0x00000000, // ICON_BOX_GRID + 0x12480000, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x7ffe1248, 0x12481248, 0x12487ffe, 0x00001248, // ICON_GRID + 0x00000000, 0x1c380000, 0x1c3817e8, 0x08100810, 0x08100810, 0x17e81c38, 0x00001c38, 0x00000000, // ICON_BOX_CORNERS_SMALL + 0x700e0000, 0x700e5ffa, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x5ffa700e, 0x0000700e, // ICON_BOX_CORNERS_BIG + 0x3f7e0000, 0x21422142, 0x21422142, 0x00003f7e, 0x21423f7e, 0x21422142, 0x3f7e2142, 0x00000000, // ICON_FOUR_BOXES + 0x00000000, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x3bb80000, 0x3bb83bb8, 0x00000000, // ICON_GRID_FILL + 0x7ffe0000, 0x7ffe7ffe, 0x77fe7000, 0x77fe77fe, 0x777e7700, 0x777e777e, 0x777e777e, 0x0000777e, // ICON_BOX_MULTISIZE + 0x781e0000, 0x40024002, 0x00004002, 0x01800000, 0x00000180, 0x40020000, 0x40024002, 0x0000781e, // ICON_ZOOM_SMALL + 0x781e0000, 0x40024002, 0x00004002, 0x03c003c0, 0x03c003c0, 0x40020000, 0x40024002, 0x0000781e, // ICON_ZOOM_MEDIUM + 0x781e0000, 0x40024002, 0x07e04002, 0x07e007e0, 0x07e007e0, 0x400207e0, 0x40024002, 0x0000781e, // ICON_ZOOM_BIG + 0x781e0000, 0x5ffa4002, 0x1ff85ffa, 0x1ff81ff8, 0x1ff81ff8, 0x5ffa1ff8, 0x40025ffa, 0x0000781e, // ICON_ZOOM_ALL + 0x00000000, 0x2004381c, 0x00002004, 0x00000000, 0x00000000, 0x20040000, 0x381c2004, 0x00000000, // ICON_ZOOM_CENTER + 0x00000000, 0x1db80000, 0x10081008, 0x10080000, 0x00001008, 0x10081008, 0x00001db8, 0x00000000, // ICON_BOX_DOTS_SMALL + 0x35560000, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x00002002, 0x35562002, 0x00000000, // ICON_BOX_DOTS_BIG + 0x7ffe0000, 0x40024002, 0x48124ff2, 0x49924812, 0x48124992, 0x4ff24812, 0x40024002, 0x00007ffe, // ICON_BOX_CONCENTRIC + 0x00000000, 0x10841ffc, 0x10841084, 0x1ffc1084, 0x10841084, 0x10841084, 0x00001ffc, 0x00000000, // ICON_BOX_GRID_BIG + 0x00000000, 0x00000000, 0x10000000, 0x04000800, 0x01040200, 0x00500088, 0x00000020, 0x00000000, // ICON_OK_TICK + 0x00000000, 0x10080000, 0x04200810, 0x01800240, 0x02400180, 0x08100420, 0x00001008, 0x00000000, // ICON_CROSS + 0x00000000, 0x02000000, 0x00800100, 0x00200040, 0x00200010, 0x00800040, 0x02000100, 0x00000000, // ICON_ARROW_LEFT + 0x00000000, 0x00400000, 0x01000080, 0x04000200, 0x04000800, 0x01000200, 0x00400080, 0x00000000, // ICON_ARROW_RIGHT + 0x00000000, 0x00000000, 0x00000000, 0x08081004, 0x02200410, 0x00800140, 0x00000000, 0x00000000, // ICON_ARROW_DOWN + 0x00000000, 0x00000000, 0x01400080, 0x04100220, 0x10040808, 0x00000000, 0x00000000, 0x00000000, // ICON_ARROW_UP + 0x00000000, 0x02000000, 0x03800300, 0x03e003c0, 0x03e003f0, 0x038003c0, 0x02000300, 0x00000000, // ICON_ARROW_LEFT_FILL + 0x00000000, 0x00400000, 0x01c000c0, 0x07c003c0, 0x07c00fc0, 0x01c003c0, 0x004000c0, 0x00000000, // ICON_ARROW_RIGHT_FILL + 0x00000000, 0x00000000, 0x00000000, 0x0ff81ffc, 0x03e007f0, 0x008001c0, 0x00000000, 0x00000000, // ICON_ARROW_DOWN_FILL + 0x00000000, 0x00000000, 0x01c00080, 0x07f003e0, 0x1ffc0ff8, 0x00000000, 0x00000000, 0x00000000, // ICON_ARROW_UP_FILL + 0x00000000, 0x18a008c0, 0x32881290, 0x24822686, 0x26862482, 0x12903288, 0x08c018a0, 0x00000000, // ICON_AUDIO + 0x00000000, 0x04800780, 0x004000c0, 0x662000f0, 0x08103c30, 0x130a0e18, 0x0000318e, 0x00000000, // ICON_FX + 0x00000000, 0x00800000, 0x08880888, 0x2aaa0a8a, 0x0a8a2aaa, 0x08880888, 0x00000080, 0x00000000, // ICON_WAVE + 0x00000000, 0x00600000, 0x01080090, 0x02040108, 0x42044204, 0x24022402, 0x00001800, 0x00000000, // ICON_WAVE_SINUS + 0x00000000, 0x07f80000, 0x04080408, 0x04080408, 0x04080408, 0x7c0e0408, 0x00000000, 0x00000000, // ICON_WAVE_SQUARE + 0x00000000, 0x00000000, 0x00a00040, 0x22084110, 0x08021404, 0x00000000, 0x00000000, 0x00000000, // ICON_WAVE_TRIANGULAR + 0x00000000, 0x00000000, 0x04200000, 0x01800240, 0x02400180, 0x00000420, 0x00000000, 0x00000000, // ICON_CROSS_SMALL + 0x00000000, 0x18380000, 0x12281428, 0x10a81128, 0x112810a8, 0x14281228, 0x00001838, 0x00000000, // ICON_PLAYER_PREVIOUS + 0x00000000, 0x18000000, 0x11801600, 0x10181060, 0x10601018, 0x16001180, 0x00001800, 0x00000000, // ICON_PLAYER_PLAY_BACK + 0x00000000, 0x00180000, 0x01880068, 0x18080608, 0x06081808, 0x00680188, 0x00000018, 0x00000000, // ICON_PLAYER_PLAY + 0x00000000, 0x1e780000, 0x12481248, 0x12481248, 0x12481248, 0x12481248, 0x00001e78, 0x00000000, // ICON_PLAYER_PAUSE + 0x00000000, 0x1ff80000, 0x10081008, 0x10081008, 0x10081008, 0x10081008, 0x00001ff8, 0x00000000, // ICON_PLAYER_STOP + 0x00000000, 0x1c180000, 0x14481428, 0x15081488, 0x14881508, 0x14281448, 0x00001c18, 0x00000000, // ICON_PLAYER_NEXT + 0x00000000, 0x03c00000, 0x08100420, 0x10081008, 0x10081008, 0x04200810, 0x000003c0, 0x00000000, // ICON_PLAYER_RECORD + 0x00000000, 0x0c3007e0, 0x13c81818, 0x14281668, 0x14281428, 0x1c381c38, 0x08102244, 0x00000000, // ICON_MAGNET + 0x07c00000, 0x08200820, 0x3ff80820, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // ICON_LOCK_CLOSE + 0x07c00000, 0x08000800, 0x3ff80800, 0x23882008, 0x21082388, 0x20082108, 0x1ff02008, 0x00000000, // ICON_LOCK_OPEN + 0x01c00000, 0x0c180770, 0x3086188c, 0x60832082, 0x60034781, 0x30062002, 0x0c18180c, 0x01c00770, // ICON_CLOCK + 0x0a200000, 0x1b201b20, 0x04200e20, 0x04200420, 0x04700420, 0x0e700e70, 0x0e700e70, 0x04200e70, // ICON_TOOLS + 0x01800000, 0x3bdc318c, 0x0ff01ff8, 0x7c3e1e78, 0x1e787c3e, 0x1ff80ff0, 0x318c3bdc, 0x00000180, // ICON_GEAR + 0x01800000, 0x3ffc318c, 0x1c381ff8, 0x781e1818, 0x1818781e, 0x1ff81c38, 0x318c3ffc, 0x00000180, // ICON_GEAR_BIG + 0x00000000, 0x08080ff8, 0x08081ffc, 0x0aa80aa8, 0x0aa80aa8, 0x0aa80aa8, 0x08080aa8, 0x00000ff8, // ICON_BIN + 0x00000000, 0x00000000, 0x20043ffc, 0x08043f84, 0x04040f84, 0x04040784, 0x000007fc, 0x00000000, // ICON_HAND_POINTER + 0x00000000, 0x24400400, 0x00001480, 0x6efe0e00, 0x00000e00, 0x24401480, 0x00000400, 0x00000000, // ICON_LASER + 0x00000000, 0x03c00000, 0x08300460, 0x11181118, 0x11181118, 0x04600830, 0x000003c0, 0x00000000, // ICON_COIN + 0x00000000, 0x10880080, 0x06c00810, 0x366c07e0, 0x07e00240, 0x00001768, 0x04200240, 0x00000000, // ICON_EXPLOSION + 0x00000000, 0x3d280000, 0x2528252c, 0x3d282528, 0x05280528, 0x05e80528, 0x00000000, 0x00000000, // ICON_1UP + 0x01800000, 0x03c003c0, 0x018003c0, 0x0ff007e0, 0x0bd00bd0, 0x0a500bd0, 0x02400240, 0x02400240, // ICON_PLAYER + 0x01800000, 0x03c003c0, 0x118013c0, 0x03c81ff8, 0x07c003c8, 0x04400440, 0x0c080478, 0x00000000, // ICON_PLAYER_JUMP + 0x3ff80000, 0x30183ff8, 0x30183018, 0x3ff83ff8, 0x03000300, 0x03c003c0, 0x03e00300, 0x000003e0, // ICON_KEY + 0x3ff80000, 0x3ff83ff8, 0x33983ff8, 0x3ff83398, 0x3ff83ff8, 0x00000540, 0x0fe00aa0, 0x00000fe0, // ICON_DEMON + 0x00000000, 0x0ff00000, 0x20041008, 0x25442004, 0x10082004, 0x06000bf0, 0x00000300, 0x00000000, // ICON_TEXT_POPUP + 0x00000000, 0x11440000, 0x07f00be8, 0x1c1c0e38, 0x1c1c0c18, 0x07f00e38, 0x11440be8, 0x00000000, // ICON_GEAR_EX + 0x00000000, 0x20080000, 0x0c601010, 0x07c00fe0, 0x07c007c0, 0x0c600fe0, 0x20081010, 0x00000000, // ICON_CRACK + 0x00000000, 0x20080000, 0x0c601010, 0x04400fe0, 0x04405554, 0x0c600fe0, 0x20081010, 0x00000000, // ICON_CRACK_POINTS + 0x00000000, 0x00800080, 0x01c001c0, 0x1ffc3ffe, 0x03e007f0, 0x07f003e0, 0x0c180770, 0x00000808, // ICON_STAR + 0x0ff00000, 0x08180810, 0x08100818, 0x0a100810, 0x08180810, 0x08100818, 0x08100810, 0x00001ff8, // ICON_DOOR + 0x0ff00000, 0x08100810, 0x08100810, 0x10100010, 0x4f902010, 0x10102010, 0x08100010, 0x00000ff0, // ICON_EXIT + 0x00040000, 0x001f000e, 0x0ef40004, 0x12f41284, 0x0ef41214, 0x10040004, 0x7ffc3004, 0x10003000, // ICON_MODE_2D + 0x78040000, 0x501f600e, 0x0ef44004, 0x12f41284, 0x0ef41284, 0x10140004, 0x7ffc300c, 0x10003000, // ICON_MODE_3D + 0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // ICON_CUBE + 0x7fe00000, 0x5ff87ff0, 0x47fe4ffc, 0x44224402, 0x44224422, 0x241275e2, 0x0c06140a, 0x000007fe, // ICON_CUBE_FACE_TOP + 0x7fe00000, 0x50386030, 0x47c2483c, 0x443e443e, 0x443e443e, 0x241e75fe, 0x0c06140e, 0x000007fe, // ICON_CUBE_FACE_LEFT + 0x7fe00000, 0x50286030, 0x47fe4804, 0x47fe47fe, 0x47fe47fe, 0x27fe77fe, 0x0ffe17fe, 0x000007fe, // ICON_CUBE_FACE_FRONT + 0x7fe00000, 0x50286030, 0x47fe4804, 0x44224402, 0x44224422, 0x3bf27be2, 0x0bfe1bfa, 0x000007fe, // ICON_CUBE_FACE_BOTTOM + 0x7fe00000, 0x70286030, 0x7ffe7804, 0x7c227c02, 0x7c227c22, 0x3c127de2, 0x0c061c0a, 0x000007fe, // ICON_CUBE_FACE_RIGHT + 0x7fe00000, 0x6fe85ff0, 0x781e77e4, 0x7be27be2, 0x7be27be2, 0x24127be2, 0x0c06140a, 0x000007fe, // ICON_CUBE_FACE_BACK + 0x00000000, 0x2a0233fe, 0x22022602, 0x22022202, 0x2a022602, 0x00a033fe, 0x02080110, 0x00000000, // ICON_CAMERA + 0x00000000, 0x200c3ffc, 0x000c000c, 0x3ffc000c, 0x30003000, 0x30003000, 0x3ffc3004, 0x00000000, // ICON_SPECIAL + 0x00000000, 0x0022003e, 0x012201e2, 0x0100013e, 0x01000100, 0x79000100, 0x4f004900, 0x00007800, // ICON_LINK_NET + 0x00000000, 0x44007c00, 0x45004600, 0x00627cbe, 0x00620022, 0x45007cbe, 0x44004600, 0x00007c00, // ICON_LINK_BOXES + 0x00000000, 0x0044007c, 0x0010007c, 0x3f100010, 0x3f1021f0, 0x3f100010, 0x3f0021f0, 0x00000000, // ICON_LINK_MULTI + 0x00000000, 0x0044007c, 0x00440044, 0x0010007c, 0x00100010, 0x44107c10, 0x440047f0, 0x00007c00, // ICON_LINK + 0x00000000, 0x0044007c, 0x00440044, 0x0000007c, 0x00000010, 0x44007c10, 0x44004550, 0x00007c00, // ICON_LINK_BROKE + 0x02a00000, 0x22a43ffc, 0x20042004, 0x20042ff4, 0x20042ff4, 0x20042ff4, 0x20042004, 0x00003ffc, // ICON_TEXT_NOTES + 0x3ffc0000, 0x20042004, 0x245e27c4, 0x27c42444, 0x2004201e, 0x201e2004, 0x20042004, 0x00003ffc, // ICON_NOTEBOOK + 0x00000000, 0x07e00000, 0x04200420, 0x24243ffc, 0x24242424, 0x24242424, 0x3ffc2424, 0x00000000, // ICON_SUITCASE + 0x00000000, 0x0fe00000, 0x08200820, 0x40047ffc, 0x7ffc5554, 0x40045554, 0x7ffc4004, 0x00000000, // ICON_SUITCASE_ZIP + 0x00000000, 0x20043ffc, 0x3ffc2004, 0x13c81008, 0x100813c8, 0x10081008, 0x1ff81008, 0x00000000, // ICON_MAILBOX + 0x00000000, 0x40027ffe, 0x5ffa5ffa, 0x5ffa5ffa, 0x40025ffa, 0x03c07ffe, 0x1ff81ff8, 0x00000000, // ICON_MONITOR + 0x0ff00000, 0x6bfe7ffe, 0x7ffe7ffe, 0x68167ffe, 0x08106816, 0x08100810, 0x0ff00810, 0x00000000, // ICON_PRINTER + 0x3ff80000, 0xfffe2008, 0x870a8002, 0x904a888a, 0x904a904a, 0x870a888a, 0xfffe8002, 0x00000000, // ICON_PHOTO_CAMERA + 0x0fc00000, 0xfcfe0cd8, 0x8002fffe, 0x84428382, 0x84428442, 0x80028382, 0xfffe8002, 0x00000000, // ICON_PHOTO_CAMERA_FLASH + 0x00000000, 0x02400180, 0x08100420, 0x20041008, 0x23c42004, 0x22442244, 0x3ffc2244, 0x00000000, // ICON_HOUSE + 0x00000000, 0x1c700000, 0x3ff83ef8, 0x3ff83ff8, 0x0fe01ff0, 0x038007c0, 0x00000100, 0x00000000, // ICON_HEART + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xe000c000, // ICON_CORNER + 0x00000000, 0x14001c00, 0x15c01400, 0x15401540, 0x155c1540, 0x15541554, 0x1ddc1554, 0x00000000, // ICON_VERTICAL_BARS + 0x00000000, 0x03000300, 0x1b001b00, 0x1b601b60, 0x1b6c1b60, 0x1b6c1b6c, 0x1b6c1b6c, 0x00000000, // ICON_VERTICAL_BARS_FILL + 0x00000000, 0x00000000, 0x403e7ffe, 0x7ffe403e, 0x7ffe0000, 0x43fe43fe, 0x00007ffe, 0x00000000, // ICON_LIFE_BARS + 0x7ffc0000, 0x43844004, 0x43844284, 0x43844004, 0x42844284, 0x42844284, 0x40044384, 0x00007ffc, // ICON_INFO + 0x40008000, 0x10002000, 0x04000800, 0x01000200, 0x00400080, 0x00100020, 0x00040008, 0x00010002, // ICON_CROSSLINE + 0x00000000, 0x1ff01ff0, 0x18301830, 0x1f001830, 0x03001f00, 0x00000300, 0x03000300, 0x00000000, // ICON_HELP + 0x3ff00000, 0x2abc3550, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x2aac3554, 0x00003ffc, // ICON_FILETYPE_ALPHA + 0x3ff00000, 0x201c2010, 0x22442184, 0x28142424, 0x29942814, 0x2ff42994, 0x20042004, 0x00003ffc, // ICON_FILETYPE_HOME + 0x07fe0000, 0x04020402, 0x7fe20402, 0x44224422, 0x44224422, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_LAYERS_VISIBLE + 0x07fe0000, 0x04020402, 0x7c020402, 0x44024402, 0x44024402, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_LAYERS + 0x00000000, 0x40027ffe, 0x7ffe4002, 0x40024002, 0x40024002, 0x40024002, 0x7ffe4002, 0x00000000, // ICON_WINDOW + 0x09100000, 0x09f00910, 0x09100910, 0x00000910, 0x24a2779e, 0x27a224a2, 0x709e20a2, 0x00000000, // ICON_HIDPI + 0x3ff00000, 0x201c2010, 0x2a842e84, 0x2e842a84, 0x2ba42004, 0x2aa42aa4, 0x20042ba4, 0x00003ffc, // ICON_FILETYPE_BINARY + 0x00000000, 0x00000000, 0x00120012, 0x4a5e4bd2, 0x485233d2, 0x00004bd2, 0x00000000, 0x00000000, // ICON_HEX + 0x01800000, 0x381c0660, 0x23c42004, 0x23c42044, 0x13c82204, 0x08101008, 0x02400420, 0x00000180, // ICON_SHIELD + 0x007e0000, 0x20023fc2, 0x40227fe2, 0x400a403a, 0x400a400a, 0x400a400a, 0x4008400e, 0x00007ff8, // ICON_FILE_NEW + 0x00000000, 0x0042007e, 0x40027fc2, 0x44024002, 0x5f024402, 0x44024402, 0x7ffe4002, 0x00000000, // ICON_FOLDER_ADD + 0x44220000, 0x12482244, 0xf3cf0000, 0x14280420, 0x48122424, 0x08100810, 0x1ff81008, 0x03c00420, // ICON_ALARM + 0x0aa00000, 0x1ff80aa0, 0x1068700e, 0x1008706e, 0x1008700e, 0x1008700e, 0x0aa01ff8, 0x00000aa0, // ICON_CPU + 0x07e00000, 0x04201db8, 0x04a01c38, 0x04a01d38, 0x04a01d38, 0x04a01d38, 0x04201d38, 0x000007e0, // ICON_ROM + 0x00000000, 0x03c00000, 0x3c382ff0, 0x3c04380c, 0x01800000, 0x03c003c0, 0x00000180, 0x00000000, // ICON_STEP_OVER + 0x01800000, 0x01800180, 0x01800180, 0x03c007e0, 0x00000180, 0x01800000, 0x03c003c0, 0x00000180, // ICON_STEP_INTO + 0x01800000, 0x07e003c0, 0x01800180, 0x01800180, 0x00000180, 0x01800000, 0x03c003c0, 0x00000180, // ICON_STEP_OUT + 0x00000000, 0x0ff003c0, 0x181c1c34, 0x303c301c, 0x30003000, 0x1c301800, 0x03c00ff0, 0x00000000, // ICON_RESTART + 0x00000000, 0x00000000, 0x07e003c0, 0x0ff00ff0, 0x0ff00ff0, 0x03c007e0, 0x00000000, 0x00000000, // ICON_BREAKPOINT_ON + 0x00000000, 0x00000000, 0x042003c0, 0x08100810, 0x08100810, 0x03c00420, 0x00000000, 0x00000000, // ICON_BREAKPOINT_OFF + 0x00000000, 0x00000000, 0x1ff81ff8, 0x1ff80000, 0x00001ff8, 0x1ff81ff8, 0x00000000, 0x00000000, // ICON_BURGER_MENU + 0x00000000, 0x00000000, 0x00880070, 0x0c880088, 0x1e8810f8, 0x3e881288, 0x00000000, 0x00000000, // ICON_CASE_SENSITIVE + 0x00000000, 0x02000000, 0x07000a80, 0x07001fc0, 0x02000a80, 0x00300030, 0x00000000, 0x00000000, // ICON_REG_EXP + 0x00000000, 0x0042007e, 0x40027fc2, 0x40024002, 0x40024002, 0x40024002, 0x7ffe4002, 0x00000000, // ICON_FOLDER + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x20042004, 0x00003ffc, // ICON_FILE + 0x1ff00000, 0x20082008, 0x17d02fe8, 0x05400ba0, 0x09200540, 0x23881010, 0x2fe827c8, 0x00001ff0, // ICON_SAND_TIMER + 0x01800000, 0x02400240, 0x05a00420, 0x09900990, 0x11881188, 0x21842004, 0x40024182, 0x00003ffc, // ICON_WARNING + 0x7ffe0000, 0x4ff24002, 0x4c324ff2, 0x4f824c02, 0x41824f82, 0x41824002, 0x40024182, 0x00007ffe, // ICON_HELP_BOX + 0x7ffe0000, 0x41824002, 0x40024182, 0x41824182, 0x41824182, 0x41824182, 0x40024182, 0x00007ffe, // ICON_INFO_BOX + 0x01800000, 0x04200240, 0x10080810, 0x7bde2004, 0x0a500a50, 0x08500bd0, 0x08100850, 0x00000ff0, // ICON_PRIORITY + 0x01800000, 0x18180660, 0x80016006, 0x98196006, 0x99996666, 0x19986666, 0x01800660, 0x00000000, // ICON_LAYERS_ISO + 0x07fe0000, 0x1c020402, 0x74021402, 0x54025402, 0x54025402, 0x500857fe, 0x40205ff8, 0x00007fe0, // ICON_LAYERS2 + 0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x422a422a, 0x422e422a, 0x40384e28, 0x00007fe0, // ICON_MLAYERS + 0x0ffe0000, 0x3ffa0802, 0x7fea200a, 0x402a402a, 0x5b2a512a, 0x512e552a, 0x40385128, 0x00007fe0, // ICON_MAPS + 0x04200000, 0x1cf00c60, 0x11f019f0, 0x0f3807b8, 0x1e3c0f3c, 0x1c1c1e1c, 0x1e3c1c1c, 0x00000f70, // ICON_HOT + 0x00000000, 0x20803f00, 0x2a202e40, 0x20082e10, 0x08021004, 0x02040402, 0x00900108, 0x00000060, // ICON_LABEL + 0x00000000, 0x042007e0, 0x47e27c3e, 0x4ffa4002, 0x47fa4002, 0x4ffa4002, 0x7ffe4002, 0x00000000, // ICON_NAME_ID + 0x7fe00000, 0x402e4020, 0x43ce5e0a, 0x40504078, 0x438e4078, 0x402e5e0a, 0x7fe04020, 0x00000000, // ICON_SLICING + 0x00000000, 0x40027ffe, 0x47c24002, 0x55425d42, 0x55725542, 0x50125552, 0x10105016, 0x00001ff0, // ICON_MANUAL_CONTROL + 0x7ffe0000, 0x43c24002, 0x48124422, 0x500a500a, 0x500a500a, 0x44224812, 0x400243c2, 0x00007ffe, // ICON_COLLISION + 0x03c00000, 0x10080c30, 0x21842184, 0x4ff24182, 0x41824ff2, 0x21842184, 0x0c301008, 0x000003c0, // ICON_CIRCLE_ADD + 0x03c00000, 0x1ff80ff0, 0x3e7c3e7c, 0x700e7e7e, 0x7e7e700e, 0x3e7c3e7c, 0x0ff01ff8, 0x000003c0, // ICON_CIRCLE_ADD_FILL + 0x03c00000, 0x10080c30, 0x21842184, 0x41824182, 0x40024182, 0x21842184, 0x0c301008, 0x000003c0, // ICON_CIRCLE_WARNING + 0x03c00000, 0x1ff80ff0, 0x3e7c3e7c, 0x7e7e7e7e, 0x7ffe7e7e, 0x3e7c3e7c, 0x0ff01ff8, 0x000003c0, // ICON_CIRCLE_WARNING_FILL + 0x00000000, 0x10041ffc, 0x10841004, 0x13e41084, 0x10841084, 0x10041004, 0x00001ffc, 0x00000000, // ICON_BOX_MORE + 0x00000000, 0x1ffc1ffc, 0x1f7c1ffc, 0x1c1c1f7c, 0x1f7c1f7c, 0x1ffc1ffc, 0x00001ffc, 0x00000000, // ICON_BOX_MORE_FILL + 0x00000000, 0x1ffc1ffc, 0x1ffc1ffc, 0x1c1c1ffc, 0x1ffc1ffc, 0x1ffc1ffc, 0x00001ffc, 0x00000000, // ICON_BOX_MINUS + 0x00000000, 0x10041ffc, 0x10041004, 0x13e41004, 0x10041004, 0x10041004, 0x00001ffc, 0x00000000, // ICON_BOX_MINUS_FILL + 0x07fe0000, 0x055606aa, 0x7ff606aa, 0x55766eba, 0x55766eaa, 0x55606ffe, 0x55606aa0, 0x00007fe0, // ICON_UNION + 0x07fe0000, 0x04020402, 0x7fe20402, 0x456246a2, 0x456246a2, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_INTERSECTION + 0x07fe0000, 0x055606aa, 0x7ff606aa, 0x4436442a, 0x4436442a, 0x402047fe, 0x40204020, 0x00007fe0, // ICON_DIFFERENCE + 0x03c00000, 0x10080c30, 0x20042004, 0x60064002, 0x47e2581a, 0x20042004, 0x0c301008, 0x000003c0, // ICON_SPHERE + 0x03e00000, 0x08080410, 0x0c180808, 0x08080be8, 0x08080808, 0x08080808, 0x04100808, 0x000003e0, // ICON_CYLINDER + 0x00800000, 0x01400140, 0x02200220, 0x04100410, 0x08080808, 0x1c1c13e4, 0x08081004, 0x000007f0, // ICON_CONE + 0x00000000, 0x07e00000, 0x20841918, 0x40824082, 0x40824082, 0x19182084, 0x000007e0, 0x00000000, // ICON_ELLIPSOID + 0x00000000, 0x00000000, 0x20041ff8, 0x40024002, 0x40024002, 0x1ff82004, 0x00000000, 0x00000000, // ICON_CAPSULE + 0x3ff00000, 0x201c2010, 0x21042004, 0x22842384, 0x264426c4, 0x2c242fe4, 0x20043e74, 0x00003ffc, // ICON_FILETYPE_FONT + 0x3ff00000, 0x201c2010, 0x20042004, 0x27742004, 0x29742944, 0x27742944, 0x20042004, 0x00003ffc, // ICON_FILETYPE_3D + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x24242244, 0x24242814, 0x20042244, 0x00003ffc, // ICON_FILETYPE_XML + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x21042f04, 0x21042104, 0x20042f04, 0x00003ffc, // ICON_FILETYPE_C + 0x3ff00000, 0x201c2010, 0x23842004, 0x2bf42a04, 0x2fd42814, 0x21c42054, 0x20042004, 0x00003ffc, // ICON_FILETYPE_PYTHON + 0x3ff00000, 0x201c2010, 0x20042004, 0x20042004, 0x22842ee4, 0x28a42e84, 0x20042e64, 0x00003ffc, // ICON_FILETYPE_JS + 0x3ff00000, 0x241c2010, 0x2a8c3104, 0x28242454, 0x2ed42004, 0x2a542a54, 0x20042ed4, 0x00003ffc, // ICON_FILETYPE_ICON + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, // ICON_257 +}; + +// NOTE: A pointer to current icons array should be defined +static unsigned int *guiIconsPtr = guiIcons; + +#endif // !RAYGUI_NO_ICONS && !RAYGUI_CUSTOM_ICONS + +#ifndef RAYGUI_ICON_SIZE + #define RAYGUI_ICON_SIZE 0 +#endif + +// WARNING: Those values define the total size of the style data array, +// if changed, previous saved styles could become incompatible +#define RAYGUI_MAX_CONTROLS 16 // Maximum number of controls +#define RAYGUI_MAX_PROPS_BASE 16 // Maximum number of base properties +#define RAYGUI_MAX_PROPS_EXTENDED 8 // Maximum number of extended properties + +//---------------------------------------------------------------------------------- +// Module Types and Structures Definition +//---------------------------------------------------------------------------------- +// Gui control property style color element +typedef enum { BORDER = 0, BASE, TEXT, OTHER } GuiPropertyElement; + +//---------------------------------------------------------------------------------- +// Global Variables Definition +//---------------------------------------------------------------------------------- +static GuiState guiState = STATE_NORMAL; // Gui global state, if !STATE_NORMAL, forces defined state + +static Font guiFont = { 0 }; // Gui current font (WARNING: highly coupled to raylib) +static char guiFontName[32] = { 0 }; // Gui font filename, can be loaded from .rgs (Version: >=600) +static bool guiLocked = false; // Gui lock state (no inputs processed) +static float guiAlpha = 1.0f; // Gui controls transparency + +static unsigned int guiIconScale = 1; // Gui icon default scale (if icons enabled) +static unsigned int guiIconFontOffsetY = 0; // Gui icon font atlas offset (if icons backed) + +static bool guiTooltip = false; // Tooltip enabled/disabled +static const char *guiTooltipPtr = NULL; // Tooltip string pointer (string provided by user) + +static bool guiControlExclusiveMode = false; // Gui control exclusive mode (no inputs processed except current control) +static Rectangle guiControlExclusiveRec = { 0 }; // Gui control exclusive bounds rectangle, used as an unique identifier + +static int textBoxCursorIndex = 0; // Cursor index, shared by all GuiTextBox*() +//static int blinkCursorFrameCounter = 0; // Frame counter for cursor blinking +static int autoCursorCounter = 0; // Frame counter for automatic repeated cursor movement on key-down (cooldown and delay) + +//---------------------------------------------------------------------------------- +// Style data array for all gui style properties (allocated on data segment by default) +// +// NOTE 1: First set of BASE properties are generic to all controls but could be individually +// overwritten per control, first set of EXTENDED properties are generic to all controls and +// can not be overwritten individually but custom EXTENDED properties can be used by control +// +// NOTE 2: A new style set could be loaded over this array using GuiLoadStyle(), +// but default gui style could always be recovered with GuiLoadStyleDefault() +// +// guiStyle size is by default: 16*(16 + 8) = 384*4 = 1536 bytes = 1.5 KB +//---------------------------------------------------------------------------------- +static unsigned int guiStyle[RAYGUI_MAX_CONTROLS*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED)] = { 0 }; + +static bool guiStyleLoaded = false; // Style loaded flag for lazy style initialization + +//---------------------------------------------------------------------------------- +// Standalone Mode Functions Declaration +// +// NOTE: raygui depend on some raylib input and drawing functions +// To use raygui as standalone library, below functions must be defined by the user +//---------------------------------------------------------------------------------- +#if defined(RAYGUI_STANDALONE) + +#define KEY_RIGHT 262 +#define KEY_LEFT 263 +#define KEY_DOWN 264 +#define KEY_UP 265 +#define KEY_BACKSPACE 259 +#define KEY_ENTER 257 + +#define MOUSE_LEFT_BUTTON 0 + +// Input required functions +//------------------------------------------------------------------------------- +static Vector2 GetMousePosition(void); +static float GetMouseWheelMove(void); +static bool IsMouseButtonDown(int button); +static bool IsMouseButtonPressed(int button); +static bool IsMouseButtonReleased(int button); + +static bool IsKeyDown(int key); +static bool IsKeyPressed(int key); +static int GetCharPressed(void); // -- GuiTextBox(), GuiValueBox() +//------------------------------------------------------------------------------- + +// Drawing required functions +//------------------------------------------------------------------------------- +static void DrawRectangle(int x, int y, int width, int height, Color color); // -- GuiDrawRectangle() +static void DrawRectangleGradientEx(Rectangle rec, Color col1, Color col2, Color col3, Color col4); // -- GuiColorPicker() +//------------------------------------------------------------------------------- + +// Text required functions +//------------------------------------------------------------------------------- +static Font GetFontDefault(void); // -- GuiLoadStyleDefault() +static Font LoadFontEx(const char *fileName, int fontSize, int *codepoints, int codepointCount); // -- GuiLoadStyle(), load font + +static Texture2D LoadTextureFromImage(Image image); // -- GuiLoadStyle(), required to load texture from embedded font atlas image +static void SetShapesTexture(Texture2D tex, Rectangle rec); // -- GuiLoadStyle(), required to set shapes rec to font white rec (optimization) + +static char *LoadFileText(const char *fileName); // -- GuiLoadStyle(), required to load charset data +static void UnloadFileText(char *text); // -- GuiLoadStyle(), required to unload charset data + +static const char *GetDirectoryPath(const char *filePath); // -- GuiLoadStyle(), required to find charset/font file from text .rgs + +static int *LoadCodepoints(const char *text, int *count); // -- GuiLoadStyle(), required to load required font codepoints list +static void UnloadCodepoints(int *codepoints); // -- GuiLoadStyle(), required to unload codepoints list + +static unsigned char *DecompressData(const unsigned char *compData, int compDataSize, int *dataSize); // -- GuiLoadStyle() + +static Vector2 MeasureTextEx(Font font, const char *text, float fontSize, float spacing); // Measure string size for Font +//------------------------------------------------------------------------------- + +// raylib functions already implemented in raygui +//------------------------------------------------------------------------------- +static Color GetColor(int hexValue); // Returns a Color struct from hexadecimal value +static Color Fade(Color color, float alpha); // Get color with alpha applied, alpha goes from 0.0f to 1.0f +static int ColorToInt(Color color); // Returns hexadecimal value for a Color +static bool CheckCollisionPointRec(Vector2 point, Rectangle rec); // Check if point is inside rectangle +static const char *TextFormat(const char *text, ...); // Formatting of text with variables to 'embed' +static int TextToInteger(const char *text); // Get integer value from text +static float TextToFloat(const char *text); // Get float value from text + +static int GetCodepointNext(const char *text, int *codepointSize); // Get next codepoint in a UTF-8 encoded text +static const char *CodepointToUTF8(int codepoint, int *byteSize); // Encode codepoint into UTF-8 text (char array size returned as parameter) +//------------------------------------------------------------------------------- + +#endif // RAYGUI_STANDALONE + +//---------------------------------------------------------------------------------- +// Module Internal Functions Declaration +//---------------------------------------------------------------------------------- +static int GetLineWidth(const char *text); // Get text line width (stops at '\n' or '\0') +static Rectangle GetTextBounds(int control, Rectangle bounds); // Get text bounds considering control bounds +static const char *GetTextIcon(const char *text, int *iconId); // Get text icon if provided and move text cursor + +static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint); // Gui draw text using default font +static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color); // Gui draw rectangle using default raygui style + +static char **GuiTextSplit(const char *text, char delimiter, int *count); // Split controls text into multiple strings +static Vector3 ConvertHSVtoRGB(Vector3 hsv); // Convert color data from HSV to RGB +static Vector3 ConvertRGBtoHSV(Vector3 rgb); // Convert color data from RGB to HSV + +static void GuiTooltip(Rectangle controlRec); // Draw tooltip using control rec position +static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue); // Scroll bar control, used by GuiScrollPanel() +static int GuiFontIconBaking(Image *imFont, Font font, Rectangle *whiteRec); // Update font image atlas to append raygui icons + +static Color GuiFade(Color color, float alpha); // Fade color by an alpha factor + +//---------------------------------------------------------------------------------- +// Gui Setup Functions Definition +//---------------------------------------------------------------------------------- +// Enable gui global state +// NOTE: Checking for STATE_DISABLED to avoid messing custom global state setups +void GuiEnable(void) { if (guiState == STATE_DISABLED) guiState = STATE_NORMAL; } + +// Disable gui global state +// NOTE: Checking for STATE_NORMAL to avoid messing custom global state setups +void GuiDisable(void) { if (guiState == STATE_NORMAL) guiState = STATE_DISABLED; } + +// Lock gui global state +void GuiLock(void) { guiLocked = true; } + +// Unlock gui global state +void GuiUnlock(void) { guiLocked = false; } + +// Check if gui is locked (global state) +bool GuiIsLocked(void) { return guiLocked; } + +// Set gui controls alpha global state +void GuiSetAlpha(float alpha) +{ + if (alpha < 0.0f) alpha = 0.0f; + else if (alpha > 1.0f) alpha = 1.0f; + + guiAlpha = alpha; +} + +// Set gui state (global state) +void GuiSetState(int state) { guiState = (GuiState)state; } + +// Get gui state (global state) +int GuiGetState(void) { return guiState; } + +// Set custom gui font +// NOTE: Font loading/unloading is external to raygui +void GuiSetFont(Font font) +{ + if (font.texture.id > 0) + { + // NOTE: If a font is tried to be set but default style has not been lazily loaded first, + // it will be overwritten, so default style loading needs to be forced first + if (!guiStyleLoaded) GuiLoadStyleDefault(); + + guiFont = font; + } +} + +// Get custom gui font +Font GuiGetFont(void) +{ + return guiFont; +} + +// Set control style property value +void GuiSetStyle(int control, int property, int value) +{ + if (!guiStyleLoaded) GuiLoadStyleDefault(); + guiStyle[control*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property] = value; + + // Default properties are propagated to all controls + if ((control == 0) && (property < RAYGUI_MAX_PROPS_BASE)) + { + for (int i = 1; i < RAYGUI_MAX_CONTROLS; i++) guiStyle[i*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property] = value; + } +} + +// Get control style property value +int GuiGetStyle(int control, int property) +{ + if (!guiStyleLoaded) GuiLoadStyleDefault(); + return guiStyle[control*(RAYGUI_MAX_PROPS_BASE + RAYGUI_MAX_PROPS_EXTENDED) + property]; +} + +//---------------------------------------------------------------------------------- +// Gui Controls Functions Definition +//---------------------------------------------------------------------------------- + +// Window Box control +int GuiWindowBox(Rectangle bounds, const char *title) +{ + // Window title bar height (including borders) + // NOTE: This define is also used by GuiMessageBox() and GuiTextInputBox() + #if !defined(RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT) + #define RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT 24 + #endif + + #if !defined(RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT) + #define RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT 18 + #endif + + int result = RESULT_NONE; + //GuiState state = guiState; + + int statusBarHeight = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT; + int statusBorderWidth = GuiGetStyle(STATUSBAR, BORDER_WIDTH); + + Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)statusBarHeight }; + if (bounds.height < statusBarHeight*2.0f) bounds.height = statusBarHeight*2.0f; + + const float vPadding = statusBarHeight/2.0f - RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT/2.0f; + Rectangle windowPanel = { bounds.x, bounds.y + (float)statusBarHeight - (float)statusBorderWidth, bounds.width, bounds.height - (float)statusBarHeight + (float)statusBorderWidth }; + Rectangle closeButtonRec = { statusBar.x + statusBar.width - (float)statusBorderWidth - RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT - vPadding, + statusBar.y + vPadding, RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT, RAYGUI_WINDOWBOX_CLOSEBUTTON_HEIGHT }; + + // Update control + //-------------------------------------------------------------------- + // NOTE: Logic is directly managed by button + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiPanel(windowPanel, NULL); // Draw window base + + int tempTextAlignment = GuiGetStyle(STATUSBAR, TEXT_ALIGNMENT); + GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiStatusBar(statusBar, title); // Draw window header as status bar + GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, tempTextAlignment); + + // Draw window close button + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 1); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); +#if defined(RAYGUI_NO_ICONS) + result = GuiButton(closeButtonRec, "x"); +#else + result = GuiButton(closeButtonRec, GuiIconText(ICON_CROSS_SMALL, NULL)); +#endif + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); + //-------------------------------------------------------------------- + + return result; +} + +// Group Box control with text name +int GuiGroupBox(Rectangle bounds, const char *text) +{ + #if !defined(RAYGUI_GROUPBOX_LINE_THICK) + #define RAYGUI_GROUPBOX_LINE_THICK 1 + #endif + + int result = RESULT_NONE; + GuiState state = guiState; + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, RAYGUI_GROUPBOX_LINE_THICK }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - 1, bounds.y, RAYGUI_GROUPBOX_LINE_THICK, bounds.height }, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR))); + + GuiLine(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y - GuiGetStyle(DEFAULT, TEXT_SIZE)/2, bounds.width, (float)GuiGetStyle(DEFAULT, TEXT_SIZE) }, text); + //-------------------------------------------------------------------- + + return result; +} + +// Line control +int GuiLine(Rectangle bounds, const char *text) +{ + #if !defined(RAYGUI_LINE_MARGIN_TEXT) + #define RAYGUI_LINE_MARGIN_TEXT 12 + #endif + #if !defined(RAYGUI_LINE_TEXT_PADDING) + #define RAYGUI_LINE_TEXT_PADDING 4 + #endif + + int result = RESULT_NONE; + GuiState state = guiState; + + Color color = GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)); + + // Draw control + //-------------------------------------------------------------------- + if (text == NULL) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height/2, bounds.width, 1 }, 0, BLANK, color); + else + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GuiGetTextWidth(text) + 2; + textBounds.height = bounds.height; + textBounds.x = bounds.x + RAYGUI_LINE_MARGIN_TEXT; + textBounds.y = bounds.y; + + // Draw line with embedded text label: "--- text --------------" + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height/2, RAYGUI_LINE_MARGIN_TEXT - RAYGUI_LINE_TEXT_PADDING, 1 }, 0, BLANK, color); + GuiDrawText(text, textBounds, TEXT_ALIGN_LEFT, color); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + 12 + textBounds.width + 4, bounds.y + bounds.height/2, bounds.width - textBounds.width - RAYGUI_LINE_MARGIN_TEXT - RAYGUI_LINE_TEXT_PADDING, 1 }, 0, BLANK, color); + } + //-------------------------------------------------------------------- + + return result; +} + +// Panel control +int GuiPanel(Rectangle bounds, const char *text) +{ + #if !defined(RAYGUI_PANEL_BORDER_WIDTH) + #define RAYGUI_PANEL_BORDER_WIDTH 1 + #endif + + int result = RESULT_NONE; + GuiState state = guiState; + + // Text will be drawn as a header bar (if provided) + Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT }; + if ((text != NULL) && (bounds.height < RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f)) bounds.height = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f; + + if (text != NULL) + { + // Move panel bounds after the header bar + bounds.y += (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1; + bounds.height -= (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1; + } + + // Draw control + //-------------------------------------------------------------------- + if (text != NULL) result = GuiStatusBar(statusBar, text); // Draw panel header as status bar + + GuiDrawRectangle(bounds, RAYGUI_PANEL_BORDER_WIDTH, GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BORDER_COLOR_DISABLED : (int)LINE_COLOR)), + GetColor(GuiGetStyle(DEFAULT, (state == STATE_DISABLED)? (int)BASE_COLOR_DISABLED : (int)BACKGROUND_COLOR))); + //-------------------------------------------------------------------- + + return result; +} + +// Scroll Panel control +int GuiScrollPanel(Rectangle bounds, const char *text, Rectangle content, Vector2 *scroll, Rectangle *view) +{ + #define RAYGUI_MIN_SCROLLBAR_WIDTH 40 + #define RAYGUI_MIN_SCROLLBAR_HEIGHT 40 + #define RAYGUI_MIN_MOUSE_WHEEL_SPEED 20 + + int result = RESULT_NONE; + GuiState state = guiState; + + Rectangle temp = { 0 }; + if (view == NULL) view = &temp; + + Vector2 scrollPos = { 0.0f, 0.0f }; + if (scroll != NULL) scrollPos = *scroll; + + // Text will be drawn as a header bar (if provided) + Rectangle statusBar = { bounds.x, bounds.y, bounds.width, (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT }; + if (bounds.height < RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f) bounds.height = RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT*2.0f; + + if (text != NULL) + { + // Move panel bounds after the header bar + bounds.y += (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 1; + bounds.height -= (float)RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + 1; + } + + bool hasHorizontalScrollBar = (content.width > bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false; + bool hasVerticalScrollBar = (content.height > bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH))? true : false; + + // Recheck to account for the other scrollbar being visible + if (!hasHorizontalScrollBar) hasHorizontalScrollBar = (hasVerticalScrollBar && (content.width > (bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false; + if (!hasVerticalScrollBar) hasVerticalScrollBar = (hasHorizontalScrollBar && (content.height > (bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH))))? true : false; + + int horizontalScrollBarWidth = hasHorizontalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0; + int verticalScrollBarWidth = hasVerticalScrollBar? GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH) : 0; + Rectangle horizontalScrollBar = { + (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + verticalScrollBarWidth : (float)bounds.x) + GuiGetStyle(DEFAULT, BORDER_WIDTH), + (float)bounds.y + bounds.height - horizontalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH), + (float)bounds.width - verticalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH), + (float)horizontalScrollBarWidth + }; + Rectangle verticalScrollBar = { + (float)((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)bounds.x + bounds.width - verticalScrollBarWidth - GuiGetStyle(DEFAULT, BORDER_WIDTH)), + (float)bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), + (float)verticalScrollBarWidth, + (float)bounds.height - horizontalScrollBarWidth - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) + }; + + // Make sure scroll bars have a minimum width/height + if (horizontalScrollBar.width < RAYGUI_MIN_SCROLLBAR_WIDTH) horizontalScrollBar.width = RAYGUI_MIN_SCROLLBAR_WIDTH; + if (verticalScrollBar.height < RAYGUI_MIN_SCROLLBAR_HEIGHT) verticalScrollBar.height = RAYGUI_MIN_SCROLLBAR_HEIGHT; + + // Calculate view area (area without the scrollbars) + *view = (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? + RAYGUI_CLITERAL(Rectangle){ bounds.x + verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth, bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth } : + RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.y + GuiGetStyle(DEFAULT, BORDER_WIDTH), bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth, bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth }; + + // Clip view area to the actual content size + if (view->width > content.width) view->width = content.width; + if (view->height > content.height) view->height = content.height; + + float horizontalMin = hasHorizontalScrollBar? ((GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)-verticalScrollBarWidth : 0) - (float)GuiGetStyle(DEFAULT, BORDER_WIDTH); + float horizontalMax = hasHorizontalScrollBar? content.width - bounds.width + (float)verticalScrollBarWidth + GuiGetStyle(DEFAULT, BORDER_WIDTH) - (((float)GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (float)verticalScrollBarWidth : 0) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); + float verticalMin = -(float)GuiGetStyle(DEFAULT, BORDER_WIDTH); + float verticalMax = hasVerticalScrollBar? content.height - bounds.height + (float)horizontalScrollBarWidth + (float)GuiGetStyle(DEFAULT, BORDER_WIDTH) : (float)-GuiGetStyle(DEFAULT, BORDER_WIDTH); + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check button state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + +#if defined(SUPPORT_SCROLLBAR_KEY_INPUT) + if (hasHorizontalScrollBar) + { + if (GUI_KEY_DOWN(KEY_RIGHT)) scrollPos.x -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + if (GUI_KEY_DOWN(KEY_LEFT)) scrollPos.x += GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + } + + if (hasVerticalScrollBar) + { + if (GUI_KEY_DOWN(KEY_DOWN)) scrollPos.y -= GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + if (GUI_KEY_DOWN(KEY_UP)) scrollPos.y += GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + } +#endif + float scrollDelta = GUI_SCROLL_DELTA; + + // Set scrolling speed with mouse wheel based on ratio between bounds and content + Vector2 scrollSpeed = { content.width/bounds.width, content.height/bounds.height }; + if (scrollSpeed.x < RAYGUI_MIN_MOUSE_WHEEL_SPEED) scrollSpeed.x = RAYGUI_MIN_MOUSE_WHEEL_SPEED; + if (scrollSpeed.y < RAYGUI_MIN_MOUSE_WHEEL_SPEED) scrollSpeed.y = RAYGUI_MIN_MOUSE_WHEEL_SPEED; + + // Horizontal and vertical scrolling with mouse wheel + if (hasHorizontalScrollBar && (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_LEFT_SHIFT))) scrollPos.x += scrollDelta*scrollSpeed.x; + else scrollPos.y += scrollDelta*scrollSpeed.y; // Vertical scroll + } + } + + // Normalize scroll values + if (scrollPos.x > -horizontalMin) scrollPos.x = -horizontalMin; + if (scrollPos.x < -horizontalMax) scrollPos.x = -horizontalMax; + if (scrollPos.y > -verticalMin) scrollPos.y = -verticalMin; + if (scrollPos.y < -verticalMax) scrollPos.y = -verticalMax; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (text != NULL) result = GuiStatusBar(statusBar, text); // Draw panel header as status bar + + GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background + + // Save size of the scrollbar slider + const int slider = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); + + // Draw horizontal scrollbar if visible + if (hasHorizontalScrollBar) + { + // Change scrollbar slider size to show the diff in size between the content width and the widget width + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)(((bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth)/(int)content.width)*((int)bounds.width - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - verticalScrollBarWidth))); + scrollPos.x = (float)-GuiScrollBar(horizontalScrollBar, (int)-scrollPos.x, (int)horizontalMin, (int)horizontalMax); + } + else scrollPos.x = 0.0f; + + // Draw vertical scrollbar if visible + if (hasVerticalScrollBar) + { + // Change scrollbar slider size to show the diff in size between the content height and the widget height + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)(((bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth)/(int)content.height)*((int)bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) - horizontalScrollBarWidth))); + scrollPos.y = (float)-GuiScrollBar(verticalScrollBar, (int)-scrollPos.y, (int)verticalMin, (int)verticalMax); + } + else scrollPos.y = 0.0f; + + // Draw detail corner rectangle if both scroll bars are visible + if (hasHorizontalScrollBar && hasVerticalScrollBar) + { + Rectangle corner = { (GuiGetStyle(LISTVIEW, SCROLLBAR_SIDE) == SCROLLBAR_LEFT_SIDE)? (bounds.x + GuiGetStyle(DEFAULT, BORDER_WIDTH) + 2) : (horizontalScrollBar.x + horizontalScrollBar.width + 2), verticalScrollBar.y + verticalScrollBar.height + 2, (float)horizontalScrollBarWidth - 4, (float)verticalScrollBarWidth - 4 }; + GuiDrawRectangle(corner, 0, BLANK, GetColor(GuiGetStyle(LISTVIEW, TEXT + (state*3)))); + } + + // Draw scrollbar lines depending on current state + GuiDrawRectangle(bounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + (state*3))), BLANK); + + // Set scrollbar slider size back to the way it was before + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, slider); + //-------------------------------------------------------------------- + + if (scroll != NULL) *scroll = scrollPos; + + return result; +} + +// Label control +int GuiLabel(Rectangle bounds, const char *text) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + // Update control + //-------------------------------------------------------------------- + //... + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + +// Button control, returns true when clicked +int GuiButton(Rectangle bounds, const char *text) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check button state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(BUTTON, BORDER_WIDTH), GetColor(GuiGetStyle(BUTTON, BORDER + (state*3))), GetColor(GuiGetStyle(BUTTON, BASE + (state*3)))); + GuiDrawText(text, GetTextBounds(BUTTON, bounds), GuiGetStyle(BUTTON, TEXT_ALIGNMENT), GetColor(GuiGetStyle(BUTTON, TEXT + (state*3)))); + + if (state == STATE_FOCUSED) GuiTooltip(bounds); + //------------------------------------------------------------------ + + return result; +} + +// Label button control +int GuiLabelButton(Rectangle bounds, const char *text) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + // NOTE: Force bounds.width to be all text + float textWidth = (float)GuiGetTextWidth(text); + if ((bounds.width - 2*GuiGetStyle(LABEL, BORDER_WIDTH) - 2*GuiGetStyle(LABEL, TEXT_PADDING)) < textWidth) bounds.width = textWidth + 2*GuiGetStyle(LABEL, BORDER_WIDTH) + 2*GuiGetStyle(LABEL, TEXT_PADDING) + 2; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check checkbox state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawText(text, GetTextBounds(LABEL, bounds), GuiGetStyle(LABEL, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + +// Toggle Button control +int GuiToggle(Rectangle bounds, const char *text, bool *active) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + bool temp = false; + if (active == NULL) active = &temp; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check toggle button state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else if (GUI_BUTTON_RELEASED) + { + state = STATE_NORMAL; + *active = !(*active); + + result = RESULT_CHANGED; + } + else state = STATE_FOCUSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state == STATE_NORMAL) + { + GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, ((*active)? BORDER_COLOR_PRESSED : (BORDER + state*3)))), GetColor(GuiGetStyle(TOGGLE, ((*active)? BASE_COLOR_PRESSED : (BASE + state*3))))); + GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TOGGLE, ((*active)? TEXT_COLOR_PRESSED : (TEXT + state*3))))); + } + else + { + GuiDrawRectangle(bounds, GuiGetStyle(TOGGLE, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, BORDER + state*3)), GetColor(GuiGetStyle(TOGGLE, BASE + state*3))); + GuiDrawText(text, GetTextBounds(TOGGLE, bounds), GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TOGGLE, TEXT + state*3))); + } + + if (state == STATE_FOCUSED) GuiTooltip(bounds); + //-------------------------------------------------------------------- + + return result; +} + +// Toggle Group control +int GuiToggleGroup(Rectangle bounds, const char *text, int *active) +{ + int result = RESULT_NONE; + + #if !defined(RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE) + #define RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE 256 + #endif + + // One toggle group item text + static char itemText[RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE] = { 0 }; + memset(itemText, 0, RAYGUI_TOGGLEGROUP_MAX_ITEM_TEXT_SIZE); + + int temp = 0; + int prevActive = (active == NULL)? 0 : *active; + if (active == NULL) active = &temp; + + bool toggle = false; // Required for individual toggles + + const char *textPtr = text; + bool itemReady = false; + float initBoundsX = bounds.x; + float initBoundsY = bounds.y; + + if (GuiGetStyle(TOGGLE, GROUP_WIDTH_FULL)) + { + // Calculate item width considring all horizontal items + // NOTE: bounds.height still considers individual items height + int itemCount = 1; + for (int c = 0; textPtr[c] != '\0'; c++) { if (textPtr[c] == ';') itemCount++; } + bounds.width /= itemCount; + } + + // Text parsing needed to consider potential row and col entries (vertical/horizontal layout) + // when '\n' found move vertically next toggle, when ';' found move horizontally + for (int c = 0, k = 0, itemIndex = 0, row = 0, col = 0, exit = 0; exit == 0; c++) + { + // Process text to get items one by one + // NOTE: Setting columns and rows index properly + if (textPtr[c] == '\n') + { + row++; + col = 0; + itemReady = true; + } + else if (textPtr[c] == ';') + { + col++; + itemReady = true; + } + else if (textPtr[c] == '\0') + { + itemReady = true; + exit = 1; + } + else + { + itemText[k] = textPtr[c]; + k++; + } + + if (itemReady) + { + // When a next item is ready, draw its toggle + if (itemIndex == (*active)) + { + toggle = true; + GuiToggle(bounds, itemText, &toggle); + } + else + { + toggle = false; + GuiToggle(bounds, itemText, &toggle); + if (toggle) *active = itemIndex; + } + + // Calculate next item position + bounds.x = initBoundsX + col*(bounds.width + GuiGetStyle(TOGGLE, GROUP_PADDING)); + bounds.y = initBoundsY + row*(bounds.height + GuiGetStyle(TOGGLE, GROUP_PADDING)); + + itemIndex++; + itemReady = false; + memset(itemText, 0, k + 1); + k = 0; + } + } + + if (prevActive != *active) result = RESULT_CHANGED; + + return result; +} + +// Toggle Slider control extended +int GuiToggleSlider(Rectangle bounds, const char *text, int *active) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + int temp = 0; + int prevActive = (active == NULL)? 0 : *active; + if (active == NULL) active = &temp; + + // Get substrings items from text (items pointers) + int itemCount = 0; + char **items = NULL; + + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount); + + Rectangle slider = { + 0, // Calculated later depending on the active toggle + bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING), + (bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - (itemCount + 1)*GuiGetStyle(SLIDER, SLIDER_PADDING))/itemCount, + bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) }; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else if (GUI_BUTTON_RELEASED) + { + state = STATE_PRESSED; + (*active)++; + result = 1; + } + else state = STATE_FOCUSED; + } + + if ((*active) && (state != STATE_FOCUSED)) state = STATE_PRESSED; + } + + if (*active >= itemCount) *active = 0; + slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH) + (*active + 1)*GuiGetStyle(SLIDER, SLIDER_PADDING) + (*active)*slider.width; + + if (prevActive != *active) result = RESULT_CHANGED; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), GetColor(GuiGetStyle(TOGGLE, BORDER + (state*3))), + GetColor(GuiGetStyle(TOGGLE, BASE_COLOR_NORMAL))); + + // Draw internal slider + if (state == STATE_NORMAL) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED))); + else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_FOCUSED))); + else if (state == STATE_PRESSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED))); + + // Draw text in slider + if (text != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GuiGetTextWidth(text); + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = slider.x + slider.width/2 - textBounds.width/2; + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(items[*active], textBounds, GuiGetStyle(TOGGLE, TEXT_ALIGNMENT), Fade(GetColor(GuiGetStyle(TOGGLE, TEXT + (state*3))), guiAlpha)); + } + //-------------------------------------------------------------------- + + return result; +} + +// Check Box control, returns 1 when state changed +int GuiCheckBox(Rectangle bounds, const char *text, bool *checked) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + bool temp = false; + if (checked == NULL) checked = &temp; + + Rectangle textBounds = { 0 }; + + if (text != NULL) + { + textBounds.width = (float)GuiGetTextWidth(text) + 2; + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + if (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(CHECKBOX, TEXT_PADDING); + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + Rectangle totalBounds = { + (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT)? textBounds.x : bounds.x, + bounds.y, + bounds.width + textBounds.width + GuiGetStyle(CHECKBOX, TEXT_PADDING), + bounds.height, + }; + + // Check checkbox state + if (CheckCollisionPointRec(mousePoint, totalBounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) + { + *checked = !(*checked); + + result = RESULT_CHANGED; + } + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(CHECKBOX, BORDER_WIDTH), GetColor(GuiGetStyle(CHECKBOX, BORDER + (state*3))), BLANK); + + if (*checked) + { + Rectangle check = { bounds.x + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING), + bounds.y + GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING), + bounds.width - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING)), + bounds.height - 2*(GuiGetStyle(CHECKBOX, BORDER_WIDTH) + GuiGetStyle(CHECKBOX, CHECK_PADDING)) }; + GuiDrawRectangle(check, 0, BLANK, GetColor(GuiGetStyle(CHECKBOX, TEXT + state*3))); + } + + GuiDrawText(text, textBounds, (GuiGetStyle(CHECKBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + +// Combo Box control +int GuiComboBox(Rectangle bounds, const char *text, int *active) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + int temp = 0; + int prevActive = (active == NULL)? 0 : *active; + if (active == NULL) active = &temp; + + bounds.width -= (GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH) + GuiGetStyle(COMBOBOX, COMBO_BUTTON_SPACING)); + + Rectangle selector = { (float)bounds.x + bounds.width + GuiGetStyle(COMBOBOX, COMBO_BUTTON_SPACING), + (float)bounds.y, (float)GuiGetStyle(COMBOBOX, COMBO_BUTTON_WIDTH), (float)bounds.height }; + + // Get substrings items from text (items pointers, lengths and count) + int itemCount = 0; + char **items = GuiTextSplit(text, ';', &itemCount); + + if (*active < 0) *active = 0; + else if (*active > (itemCount - 1)) *active = itemCount - 1; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && (itemCount > 1) && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (CheckCollisionPointRec(mousePoint, bounds) || + CheckCollisionPointRec(mousePoint, selector)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + + if (GUI_BUTTON_PRESSED) + { + *active += 1; + if (*active >= itemCount) *active = 0; // Cyclic combobox + } + } + } + + if (prevActive != *active) result = RESULT_CHANGED; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + // Draw combo box main + GuiDrawRectangle(bounds, GuiGetStyle(COMBOBOX, BORDER_WIDTH), GetColor(GuiGetStyle(COMBOBOX, BORDER + (state*3))), GetColor(GuiGetStyle(COMBOBOX, BASE + (state*3)))); + GuiDrawText(items[*active], GetTextBounds(COMBOBOX, bounds), GuiGetStyle(COMBOBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(COMBOBOX, TEXT + (state*3)))); + + // Draw selector using a custom button + // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 1); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + + GuiButton(selector, TextFormat("%i/%i", *active + 1, itemCount)); + + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign); + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + //-------------------------------------------------------------------- + + return result; +} + +// Dropdown Box control +// NOTE: Returns mouse click +int GuiDropdownBox(Rectangle bounds, const char *text, int *active, bool editMode) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + int temp = 0; + int prevActive = (active == NULL)? 0 : *active; + if (active == NULL) active = &temp; + + int itemSelected = *active; + int itemFocused = -1; + + int direction = 0; // Dropdown box open direction: down (default) + if (GuiGetStyle(DROPDOWNBOX, DROPDOWN_ROLL_UP) == 1) direction = 1; // Up + + // Get substrings items from text (items pointers, lengths and count) + int itemCount = 0; + char **items = GuiTextSplit(text, ';', &itemCount); + + Rectangle boundsOpen = bounds; + boundsOpen.height = (itemCount + 1)*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + if (direction == 1) boundsOpen.y -= itemCount*(bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)) + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING); + + Rectangle itemBounds = bounds; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && (editMode || !guiLocked) && (itemCount > 1) && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (editMode) + { + state = STATE_PRESSED; + + // Check if mouse has been pressed or released outside limits + if (!CheckCollisionPointRec(mousePoint, boundsOpen)) + { + if (GUI_BUTTON_PRESSED || GUI_BUTTON_RELEASED) result = 1; + } + + // Check if already selected item has been pressed again + if (CheckCollisionPointRec(mousePoint, bounds) && GUI_BUTTON_PRESSED) result = 1; + + // Check focused and selected item + for (int i = 0; i < itemCount; i++) + { + // Update item rectangle y position for next item + if (direction == 0) itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + else itemBounds.y -= (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + + if (CheckCollisionPointRec(mousePoint, itemBounds)) + { + itemFocused = i; + if (GUI_BUTTON_RELEASED) + { + itemSelected = i; + result = 1; // Item selected + } + break; + } + } + + itemBounds = bounds; + } + else + { + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_PRESSED) + { + result = 1; + state = STATE_PRESSED; + } + else state = STATE_FOCUSED; + } + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (editMode) GuiPanel(boundsOpen, NULL); + + GuiDrawRectangle(bounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER + state*3)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE + state*3))); + GuiDrawText(items[itemSelected], GetTextBounds(DROPDOWNBOX, bounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + state*3))); + + if (editMode) + { + // Draw visible items + for (int i = 0; i < itemCount; i++) + { + // Update item rectangle y position for next item + if (direction == 0) itemBounds.y += (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + else itemBounds.y -= (bounds.height + GuiGetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING)); + + if (i == itemSelected) + { + GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_PRESSED))); + GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_PRESSED))); + } + else if (i == itemFocused) + { + GuiDrawRectangle(itemBounds, GuiGetStyle(DROPDOWNBOX, BORDER_WIDTH), GetColor(GuiGetStyle(DROPDOWNBOX, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(DROPDOWNBOX, BASE_COLOR_FOCUSED))); + GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_FOCUSED))); + } + else GuiDrawText(items[i], GetTextBounds(DROPDOWNBOX, itemBounds), GuiGetStyle(DROPDOWNBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(DROPDOWNBOX, TEXT_COLOR_NORMAL))); + } + } + + if (!GuiGetStyle(DROPDOWNBOX, DROPDOWN_ARROW_HIDDEN)) + { + // Draw arrows (using icon if available) +#if defined(RAYGUI_NO_ICONS) + GuiDrawText("v", RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 2, 10, 10 }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); +#else + GuiDrawText(direction? GuiIconText(ICON_ARROW_UP_FILL, NULL) : GuiIconText(ICON_ARROW_DOWN_FILL, NULL), + RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - GuiGetStyle(DROPDOWNBOX, ARROW_PADDING), bounds.y + bounds.height/2 - 6, 10, 10 }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); // ICON_ARROW_DOWN_FILL +#endif + } + //-------------------------------------------------------------------- + + *active = itemSelected; + + if (prevActive != *active) result = RESULT_CHANGED; + + return result; +} + +// Text Box control +// NOTE: Returns true on ENTER pressed (useful for data validation) +int GuiTextBox(Rectangle bounds, char *text, int textSize, bool editMode) +{ + #if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN) + #define RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN 20 // Frames to wait for autocursor movement + #endif + #if !defined(RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) + #define RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY 1 // Frames delay for autocursor movement + #endif + + int result = RESULT_NONE; + GuiState state = guiState; + + bool multiline = false; + int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); + + Rectangle textBounds = GetTextBounds(TEXTBOX, bounds); + int textLength = (text != NULL)? (int)strlen(text) : 0; // Get current text length + int thisCursorIndex = textBoxCursorIndex; + if (thisCursorIndex > textLength) thisCursorIndex = textLength; + int textWidth = GuiGetTextWidth(text) - GuiGetTextWidth(text + thisCursorIndex); + int textIndexOffset = 0; // Text index offset to start drawing in the box + + // Cursor rectangle + // NOTE: Position X value should be updated + Rectangle cursor = { + textBounds.x + textWidth + GuiGetStyle(DEFAULT, TEXT_SPACING), + textBounds.y + textBounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE), + 2, + (float)GuiGetStyle(DEFAULT, TEXT_SIZE)*2 + }; + + if (cursor.height >= bounds.height) cursor.height = bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2; + if (cursor.y < (bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH))) cursor.y = bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH); + + // Mouse cursor rectangle + // NOTE: Initialized outside of screen + Rectangle mouseCursor = cursor; + mouseCursor.x = -1; + mouseCursor.width = 1; + + // Blink-cursor frame counter + //if (!autoCursorMode) blinkCursorFrameCounter++; + //else blinkCursorFrameCounter = 0; + + // Update control + //-------------------------------------------------------------------- + // WARNING: Text editing is only supported under certain conditions: + if ((state != STATE_DISABLED) && // Control not disabled + !GuiGetStyle(TEXTBOX, TEXT_READONLY) && // TextBox not on read-only mode + !guiLocked && // Gui not locked + !guiControlExclusiveMode && // No gui slider on dragging + (wrapMode == TEXT_WRAP_NONE)) // No wrap mode + { + Vector2 mousePosition = GUI_POINTER_POSITION; + + if (editMode) + { + // GLOBAL: Auto-cursor movement logic + // NOTE: Keystrokes are handled repeatedly when button is held down for some time + if (GUI_KEY_DOWN(KEY_LEFT) || GUI_KEY_DOWN(KEY_RIGHT) || + GUI_KEY_DOWN(KEY_UP) || GUI_KEY_DOWN(KEY_DOWN) || + GUI_KEY_DOWN(KEY_BACKSPACE) || GUI_KEY_DOWN(KEY_DELETE)) autoCursorCounter++; + else autoCursorCounter = 0; + + bool autoCursorShouldTrigger = (autoCursorCounter > RAYGUI_TEXTBOX_AUTO_CURSOR_COOLDOWN) && ((autoCursorCounter % RAYGUI_TEXTBOX_AUTO_CURSOR_DELAY) == 0); + + state = STATE_PRESSED; + + if (textBoxCursorIndex > textLength) textBoxCursorIndex = textLength; + + // If text does not fit in the textbox and current cursor position is out of bounds, + // adding an index offset to text for drawing only what requires depending on cursor + while (textWidth >= textBounds.width) + { + int nextCodepointSize = 0; + GetCodepointNext(text + textIndexOffset, &nextCodepointSize); + + textIndexOffset += nextCodepointSize; + + textWidth = GuiGetTextWidth(text + textIndexOffset) - GuiGetTextWidth(text + textBoxCursorIndex); + } + + int codepoint = GUI_INPUT_KEY; // Get Unicode codepoint + if (multiline && GUI_KEY_PRESSED(KEY_ENTER)) codepoint = (int)'\n'; + + // Encode codepoint as UTF-8 + int codepointSize = 0; + const char *charEncoded = CodepointToUTF8(codepoint, &codepointSize); + + // Handle text paste action + if (GUI_KEY_PRESSED(KEY_V) && (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) + { + const char *pasteText = GetClipboardText(); + if (pasteText != NULL) + { + int pasteLength = 0; + int pasteCodepoint; + int pasteCodepointSize; + + // Count how many codepoints to copy, stopping at the first unwanted control character + while (true) + { + pasteCodepoint = GetCodepointNext(pasteText + pasteLength, &pasteCodepointSize); + if (textLength + pasteLength + pasteCodepointSize >= textSize) break; + if (!(multiline && (pasteCodepoint == (int)'\n')) && !(pasteCodepoint >= 32)) break; + pasteLength += pasteCodepointSize; + } + + if (pasteLength > 0) + { + // Move forward data from cursor position + for (int i = textLength + pasteLength; i > textBoxCursorIndex; i--) text[i] = text[i - pasteLength]; + + // Paste data in at cursor + for (int i = 0; i < pasteLength; i++) text[textBoxCursorIndex + i] = pasteText[i]; + + textBoxCursorIndex += pasteLength; + textLength += pasteLength; + text[textLength] = '\0'; + + //result = RESULT_CHANGED; + } + } + } + else if (((multiline && (codepoint == (int)'\n')) || (codepoint >= 32)) && ((textLength + codepointSize) < textSize)) + { + // Adding codepoint to text, at current cursor position + + // Move forward data from cursor position + for (int i = (textLength + codepointSize); i > textBoxCursorIndex; i--) text[i] = text[i - codepointSize]; + + // Add new codepoint in current cursor position + for (int i = 0; i < codepointSize; i++) text[textBoxCursorIndex + i] = charEncoded[i]; + + textBoxCursorIndex += codepointSize; + textLength += codepointSize; + + // Make sure text last character is EOL + text[textLength] = '\0'; + + //result = RESULT_CHANGED; + } + + // Move cursor to start + if ((textLength > 0) && GUI_KEY_PRESSED(KEY_HOME)) textBoxCursorIndex = 0; + + // Move cursor to end + if ((textLength > textBoxCursorIndex) && GUI_KEY_PRESSED(KEY_END)) textBoxCursorIndex = textLength; + + // Delete related codepoints from text, after current cursor position + if ((textLength > textBoxCursorIndex) && GUI_KEY_PRESSED(KEY_DELETE) && (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) + { + int offset = textBoxCursorIndex; + int accCodepointSize = 0; + int nextCodepointSize; + int nextCodepoint; + + // Check characters of the same type to delete (either ASCII punctuation or anything non-whitespace) + // Not using isalnum() since it only works on ASCII characters + nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); + bool puctuation = ispunct(nextCodepoint & 0xff); + while (offset < textLength) + { + if ((puctuation && !ispunct(nextCodepoint & 0xff)) || + (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff)))) break; + + offset += nextCodepointSize; + accCodepointSize += nextCodepointSize; + nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); + } + + // Check whitespace to delete (ASCII only) + while (offset < textLength) + { + if (!isspace(nextCodepoint & 0xff)) break; + + offset += nextCodepointSize; + accCodepointSize += nextCodepointSize; + nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); + } + + // Move text after cursor forward (including final null terminator) + for (int i = offset; i <= textLength; i++) text[i - accCodepointSize] = text[i]; + + textLength -= accCodepointSize; + + //result = RESULT_CHANGED; + } + else if ((textLength > textBoxCursorIndex) && (GUI_KEY_PRESSED(KEY_DELETE) || + (GUI_KEY_DOWN(KEY_DELETE) && autoCursorShouldTrigger))) + { + // Delete single codepoint from text, after current cursor position + + int nextCodepointSize = 0; + GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize); + + // Move text after cursor forward (including final null terminator) + for (int i = textBoxCursorIndex + nextCodepointSize; i <= textLength; i++) text[i - nextCodepointSize] = text[i]; + + textLength -= nextCodepointSize; + + //result = RESULT_CHANGED; + } + + // Delete related codepoints from text, before current cursor position + if ((textBoxCursorIndex > 0) && GUI_KEY_PRESSED(KEY_BACKSPACE) && + (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) + { + int offset = textBoxCursorIndex; + int accCodepointSize = 0; + int prevCodepointSize = 0; + int prevCodepoint = 0; + + // Check whitespace to delete (ASCII only) + while (offset > 0) + { + prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize); + if (!isspace(prevCodepoint & 0xff)) break; + + offset -= prevCodepointSize; + accCodepointSize += prevCodepointSize; + } + + // Check characters of the same type to delete (either ASCII punctuation or anything non-whitespace) + // Not using isalnum() since it only works on ASCII characters + bool puctuation = ispunct(prevCodepoint & 0xff); + while (offset > 0) + { + prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize); + if ((puctuation && !ispunct(prevCodepoint & 0xff)) || + (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break; + + offset -= prevCodepointSize; + accCodepointSize += prevCodepointSize; + } + + // Move text after cursor forward (including final null terminator) + for (int i = textBoxCursorIndex; i <= textLength; i++) text[i - accCodepointSize] = text[i]; + + textLength -= accCodepointSize; + textBoxCursorIndex -= accCodepointSize; + + //result = RESULT_CHANGED; + } + else if ((textBoxCursorIndex > 0) && (GUI_KEY_PRESSED(KEY_BACKSPACE) || (GUI_KEY_DOWN(KEY_BACKSPACE) && autoCursorShouldTrigger))) + { + // Delete single codepoint from text, before current cursor position + + int prevCodepointSize = 0; + + GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize); + + // Move text after cursor forward (including final null terminator) + for (int i = textBoxCursorIndex; i <= textLength; i++) text[i - prevCodepointSize] = text[i]; + + textLength -= prevCodepointSize; + textBoxCursorIndex -= prevCodepointSize; + + //result = RESULT_CHANGED; + } + + // Move cursor position with keys + if ((textBoxCursorIndex > 0) && GUI_KEY_PRESSED(KEY_LEFT) && (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) + { + int offset = textBoxCursorIndex; + //int accCodepointSize = 0; + int prevCodepointSize = 0; + int prevCodepoint = 0; + + // Check whitespace to skip (ASCII only) + while (offset > 0) + { + prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize); + if (!isspace(prevCodepoint & 0xff)) break; + + offset -= prevCodepointSize; + //accCodepointSize += prevCodepointSize; + } + + // Check characters of the same type to skip (either ASCII punctuation or anything non-whitespace) + // Not using isalnum() since it only works on ASCII characters + bool puctuation = ispunct(prevCodepoint & 0xff); + while (offset > 0) + { + prevCodepoint = GetCodepointPrevious(text + offset, &prevCodepointSize); + if ((puctuation && !ispunct(prevCodepoint & 0xff)) || (!puctuation && (isspace(prevCodepoint & 0xff) || ispunct(prevCodepoint & 0xff)))) break; + + offset -= prevCodepointSize; + //accCodepointSize += prevCodepointSize; + } + + textBoxCursorIndex = offset; + } + else if ((textBoxCursorIndex > 0) && (GUI_KEY_PRESSED(KEY_LEFT) || (GUI_KEY_DOWN(KEY_LEFT) && autoCursorShouldTrigger))) + { + int prevCodepointSize = 0; + GetCodepointPrevious(text + textBoxCursorIndex, &prevCodepointSize); + + textBoxCursorIndex -= prevCodepointSize; + } + else if ((textLength > textBoxCursorIndex) && GUI_KEY_PRESSED(KEY_RIGHT) && (GUI_KEY_DOWN(KEY_LEFT_CONTROL) || GUI_KEY_DOWN(KEY_RIGHT_CONTROL))) + { + int offset = textBoxCursorIndex; + //int accCodepointSize = 0; + int nextCodepointSize; + int nextCodepoint; + + // Check characters of the same type to skip (either ASCII punctuation or anything non-whitespace) + // Not using isalnum() since it only works on ASCII characters + nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); + bool puctuation = ispunct(nextCodepoint & 0xff); + while (offset < textLength) + { + if ((puctuation && !ispunct(nextCodepoint & 0xff)) || (!puctuation && (isspace(nextCodepoint & 0xff) || ispunct(nextCodepoint & 0xff)))) break; + + offset += nextCodepointSize; + //accCodepointSize += nextCodepointSize; + nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); + } + + // Check whitespace to skip (ASCII only) + while (offset < textLength) + { + if (!isspace(nextCodepoint & 0xff)) break; + + offset += nextCodepointSize; + //accCodepointSize += nextCodepointSize; + nextCodepoint = GetCodepointNext(text + offset, &nextCodepointSize); + } + + textBoxCursorIndex = offset; + } + else if ((textLength > textBoxCursorIndex) && (GUI_KEY_PRESSED(KEY_RIGHT) || (GUI_KEY_DOWN(KEY_RIGHT) && autoCursorShouldTrigger))) + { + int nextCodepointSize = 0; + GetCodepointNext(text + textBoxCursorIndex, &nextCodepointSize); + + textBoxCursorIndex += nextCodepointSize; + } + + // Move cursor position with mouse + if (CheckCollisionPointRec(mousePosition, textBounds)) + { + float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/(float)guiFont.baseSize; + int codepointIndex = 0; + float glyphWidth = 0.0f; + float widthToMouseX = 0; + int mouseCursorIndex = 0; + + for (int i = textIndexOffset; i < textLength; i += codepointSize) + { + codepoint = GetCodepointNext(&text[i], &codepointSize); + codepointIndex = GetGlyphIndex(guiFont, codepoint); + + if (guiFont.glyphs[codepointIndex].advanceX == 0) glyphWidth = ((float)guiFont.recs[codepointIndex].width*scaleFactor); + else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor); + + if (mousePosition.x <= (textBounds.x + (widthToMouseX + glyphWidth/2))) + { + mouseCursor.x = textBounds.x + widthToMouseX; + mouseCursorIndex = i; + break; + } + + widthToMouseX += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + } + + // Check if mouse cursor is at the last position + int textEndWidth = GuiGetTextWidth(text + textIndexOffset); + if (GUI_POINTER_POSITION.x >= (textBounds.x + textEndWidth - glyphWidth/2)) + { + mouseCursor.x = textBounds.x + textEndWidth; + mouseCursorIndex = textLength; + } + + // Place cursor at required index on mouse click + if ((mouseCursor.x >= 0) && GUI_BUTTON_PRESSED) + { + cursor.x = mouseCursor.x; + textBoxCursorIndex = mouseCursorIndex; + } + } + else mouseCursor.x = -1; + + // Recalculate cursor position.y depending on textBoxCursorIndex + cursor.x = bounds.x + GuiGetStyle(TEXTBOX, TEXT_PADDING) + GuiGetTextWidth(text + textIndexOffset) - GuiGetTextWidth(text + textBoxCursorIndex) + GuiGetStyle(DEFAULT, TEXT_SPACING); + //if (multiline) cursor.y = GetTextLines() + + // Finish text editing on ENTER or mouse click outside bounds + if ((!multiline && GUI_KEY_PRESSED(KEY_ENTER)) || + (!CheckCollisionPointRec(mousePosition, bounds) && GUI_BUTTON_PRESSED)) + { + textBoxCursorIndex = 0; // GLOBAL: Reset the shared cursor index + autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes + + //*editMode = false; + result = RESULT_PRESSED; + } + } + else + { + if (CheckCollisionPointRec(mousePosition, bounds)) + { + state = STATE_FOCUSED; + + if (GUI_BUTTON_PRESSED) + { + textBoxCursorIndex = textLength; // GLOBAL: Place cursor index to the end of current text + autoCursorCounter = 0; // GLOBAL: Reset counter for repeated keystrokes + + //*editMode = true; + result = RESULT_PRESSED; + } + } + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state == STATE_PRESSED) + { + GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_PRESSED))); + } + else if (state == STATE_DISABLED) + { + GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), GetColor(GuiGetStyle(TEXTBOX, BASE_COLOR_DISABLED))); + } + else GuiDrawRectangle(bounds, GuiGetStyle(TEXTBOX, BORDER_WIDTH), GetColor(GuiGetStyle(TEXTBOX, BORDER + (state*3))), BLANK); + + // Draw text considering index offset if required + // NOTE: Text index offset depends on cursor position + GuiDrawText(text + textIndexOffset, textBounds, GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT), GetColor(GuiGetStyle(TEXTBOX, TEXT + (state*3)))); + + // Draw cursor + if (editMode && !GuiGetStyle(TEXTBOX, TEXT_READONLY)) + { + //if (autoCursorMode || ((blinkCursorFrameCounter/40)%2 == 0)) + GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED))); + + // Draw mouse position cursor (if required) + if (mouseCursor.x >= 0) GuiDrawRectangle(mouseCursor, 0, BLANK, GetColor(GuiGetStyle(TEXTBOX, BORDER_COLOR_PRESSED))); + } + else if (state == STATE_FOCUSED) GuiTooltip(bounds); + //-------------------------------------------------------------------- + + return result; +} + +/* +// Text Box control with multiple lines and word-wrap +// NOTE: This text-box is readonly, no editing supported by default +bool GuiTextBoxMulti(Rectangle bounds, char *text, int textSize, bool editMode) +{ + bool pressed = false; + + GuiSetStyle(TEXTBOX, TEXT_READONLY, 1); + GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_WORD); // WARNING: If wrap mode enabled, text editing is not supported + GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_TOP); + + // TODO: Implement methods to calculate cursor position properly + pressed = GuiTextBox(bounds, text, textSize, editMode); + + GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); + GuiSetStyle(DEFAULT, TEXT_WRAP_MODE, TEXT_WRAP_NONE); + GuiSetStyle(TEXTBOX, TEXT_READONLY, 0); + + return pressed; +} +*/ + +// Spinner control, returns selected value +int GuiSpinner(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) +{ + int result = 1; + GuiState state = guiState; + + int tempValue = *value; + + Rectangle valueBoxBounds = { + bounds.x + GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH) + GuiGetStyle(VALUEBOX, SPINNER_BUTTON_SPACING), + bounds.y, + bounds.width - 2*(GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH) + GuiGetStyle(VALUEBOX, SPINNER_BUTTON_SPACING)), bounds.height }; + Rectangle leftButtonBound = { (float)bounds.x, (float)bounds.y, (float)GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH), (float)bounds.height }; + Rectangle rightButtonBound = { (float)bounds.x + bounds.width - GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH), (float)bounds.y, + (float)GuiGetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH), (float)bounds.height }; + + Rectangle textBounds = { 0 }; + if (text != NULL) + { + textBounds.width = (float)GuiGetTextWidth(text) + 2; + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING); + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check spinner state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + } + } + +#if defined(RAYGUI_NO_ICONS) + if (GuiButton(leftButtonBound, "<")) tempValue--; + if (GuiButton(rightButtonBound, ">")) tempValue++; +#else + if (GuiButton(leftButtonBound, GuiIconText(ICON_ARROW_LEFT_FILL, NULL))) tempValue--; + if (GuiButton(rightButtonBound, GuiIconText(ICON_ARROW_RIGHT_FILL, NULL))) tempValue++; +#endif + + if (!editMode) + { + if (tempValue < minValue) tempValue = minValue; + if (tempValue > maxValue) tempValue = maxValue; + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + result = GuiValueBox(valueBoxBounds, NULL, &tempValue, minValue, maxValue, editMode); + + // Draw value selector custom buttons + // NOTE: BORDER_WIDTH and TEXT_ALIGNMENT forced values + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlign = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, GuiGetStyle(VALUEBOX, BORDER_WIDTH)); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlign); + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + + // Draw text label if provided + GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + //if (tempValue != *value) result = RESULT_CHANGED; // WARNING: Stops editing + + *value = tempValue; + + return result; +} + +// Value Box control, updates input text with numbers +int GuiValueBox(Rectangle bounds, const char *text, int *value, int minValue, int maxValue, bool editMode) +{ + #if !defined(RAYGUI_VALUEBOX_MAX_CHARS) + #define RAYGUI_VALUEBOX_MAX_CHARS 32 + #endif + + int result = RESULT_NONE; + GuiState state = guiState; + + //int prevValue = *value; + char textValue[RAYGUI_VALUEBOX_MAX_CHARS + 1] = { 0 }; + snprintf(textValue, RAYGUI_VALUEBOX_MAX_CHARS + 1, "%i", *value); + + Rectangle textBounds = { 0 }; + if (text != NULL) + { + textBounds.width = (float)GuiGetTextWidth(text) + 2; + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING); + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + bool valueHasChanged = false; + + if (editMode) + { + state = STATE_PRESSED; + + int keyCount = (int)strlen(textValue); + + // Add or remove minus symbol + if (GUI_KEY_PRESSED(KEY_MINUS)) + { + if (textValue[0] == '-') + { + for (int i = 0 ; i < keyCount; i++) textValue[i] = textValue[i + 1]; + + keyCount--; + valueHasChanged = true; + } + else if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) + { + if (keyCount == 0) + { + textValue[0] = '0'; + textValue[1] = '\0'; + keyCount++; + } + + for (int i = keyCount ; i > -1; i--) textValue[i + 1] = textValue[i]; + + textValue[0] = '-'; + keyCount++; + valueHasChanged = true; + } + } + + // Add new digit to text value + if ((keyCount >= 0) && (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) && (GuiGetTextWidth(textValue) < bounds.width)) + { + int key = GUI_INPUT_KEY; + + // Only allow keys in range [48..57] + if ((key >= 48) && (key <= 57)) + { + textValue[keyCount] = (char)key; + keyCount++; + valueHasChanged = true; + } + } + + // Delete text + if ((keyCount > 0) && GUI_KEY_PRESSED(KEY_BACKSPACE)) + { + keyCount--; + textValue[keyCount] = '\0'; + valueHasChanged = true; + } + + if (valueHasChanged) *value = TextToInteger(textValue); + + // NOTE: Values are not clamped until user input finishes + //if (*value > maxValue) *value = maxValue; + //else if (*value < minValue) *value = minValue; + + if ((GUI_KEY_PRESSED(KEY_ENTER) || GUI_KEY_PRESSED(KEY_KP_ENTER)) || (!CheckCollisionPointRec(mousePoint, bounds) && GUI_BUTTON_PRESSED)) + { + if (*value > maxValue) *value = maxValue; + else if (*value < minValue) *value = minValue; + + result = RESULT_PRESSED; + } + } + else + { + if (*value > maxValue) *value = maxValue; + else if (*value < minValue) *value = minValue; + + if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + + if (GUI_BUTTON_PRESSED) result = RESULT_PRESSED; + } + } + } + + //if (prevValue != *value) result = RESULT_CHANGED; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + Color baseColor = BLANK; + if (state == STATE_PRESSED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_PRESSED)); + else if (state == STATE_DISABLED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_DISABLED)); + + GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), baseColor); + GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3)))); + + // Draw cursor rectangle + if (editMode) + { + // NOTE: ValueBox internal text is always centered + Rectangle cursor = { bounds.x + GuiGetTextWidth(textValue)/2 + bounds.width/2 + 1, + bounds.y + GuiGetStyle(TEXTBOX, BORDER_WIDTH) + 2, + 2, bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2 - 4 }; + if (cursor.height > bounds.height) cursor.height = bounds.height - GuiGetStyle(TEXTBOX, BORDER_WIDTH)*2; + GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED))); + } + + // Draw text label if provided + GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + +// Floating point Value Box control, updates input val_str with numbers +int GuiValueBoxFloat(Rectangle bounds, const char *text, char *textValue, float *value, bool editMode) +{ + #if !defined(RAYGUI_VALUEBOX_MAX_CHARS) + #define RAYGUI_VALUEBOX_MAX_CHARS 32 + #endif + + int result = RESULT_NONE; + GuiState state = guiState; + + //float prevValue = *value; + + Rectangle textBounds = { 0 }; + if (text != NULL) + { + textBounds.width = (float)GuiGetTextWidth(text) + 2; + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(VALUEBOX, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + if (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_LEFT) textBounds.x = bounds.x - textBounds.width - GuiGetStyle(VALUEBOX, TEXT_PADDING); + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + bool valueHasChanged = false; + + if (editMode) + { + state = STATE_PRESSED; + + int keyCount = (int)strlen(textValue); + + // Add or remove minus symbol + if (GUI_KEY_PRESSED(KEY_MINUS)) + { + if (textValue[0] == '-') + { + for (int i = 0; i < keyCount; i++) textValue[i] = textValue[i + 1]; + + keyCount--; + valueHasChanged = true; + } + else if (keyCount < (RAYGUI_VALUEBOX_MAX_CHARS - 1)) + { + if (keyCount == 0) + { + textValue[0] = '0'; + textValue[1] = '\0'; + keyCount++; + } + + for (int i = keyCount; i > -1; i--) textValue[i + 1] = textValue[i]; + + textValue[0] = '-'; + keyCount++; + valueHasChanged = true; + } + } + + // Only allow keys in range [48..57] + if (keyCount < RAYGUI_VALUEBOX_MAX_CHARS) + { + if (GuiGetTextWidth(textValue) < bounds.width) + { + int key = GUI_INPUT_KEY; + if (((key >= 48) && (key <= 57)) || + (key == '.') || + ((keyCount == 0) && (key == '+')) || // NOTE: Sign can only be in first position + ((keyCount == 0) && (key == '-'))) + { + textValue[keyCount] = (char)key; + keyCount++; + + valueHasChanged = true; + } + } + } + + // Pressed backspace + if (GUI_KEY_PRESSED(KEY_BACKSPACE)) + { + if (keyCount > 0) + { + keyCount--; + textValue[keyCount] = '\0'; + valueHasChanged = true; + } + } + + if (valueHasChanged) *value = TextToFloat(textValue); + + if ((GUI_KEY_PRESSED(KEY_ENTER) || GUI_KEY_PRESSED(KEY_KP_ENTER)) || + (!CheckCollisionPointRec(mousePoint, bounds) && GUI_BUTTON_PRESSED)) result = RESULT_PRESSED; + } + else + { + if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + + if (GUI_BUTTON_PRESSED) result = RESULT_PRESSED; + } + } + } + + //if (prevValue != *value) result = RESULT_CHANGED; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + Color baseColor = BLANK; + if (state == STATE_PRESSED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_PRESSED)); + else if (state == STATE_DISABLED) baseColor = GetColor(GuiGetStyle(VALUEBOX, BASE_COLOR_DISABLED)); + + GuiDrawRectangle(bounds, GuiGetStyle(VALUEBOX, BORDER_WIDTH), GetColor(GuiGetStyle(VALUEBOX, BORDER + (state*3))), baseColor); + GuiDrawText(textValue, GetTextBounds(VALUEBOX, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(VALUEBOX, TEXT + (state*3)))); + + // Draw cursor + if (editMode) + { + // NOTE: ValueBox internal text is always centered + Rectangle cursor = {bounds.x + GuiGetTextWidth(textValue)/2 + bounds.width/2 + 1, + bounds.y + 2*GuiGetStyle(VALUEBOX, BORDER_WIDTH), 4, + bounds.height - 4*GuiGetStyle(VALUEBOX, BORDER_WIDTH)}; + GuiDrawRectangle(cursor, 0, BLANK, GetColor(GuiGetStyle(VALUEBOX, BORDER_COLOR_PRESSED))); + } + + // Draw text label if provided + GuiDrawText(text, textBounds, (GuiGetStyle(VALUEBOX, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT)? TEXT_ALIGN_LEFT : TEXT_ALIGN_RIGHT, + GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + +// Slider control with pro parameters +// NOTE: Other GuiSlider*() controls use this one +int GuiSlider(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + float temp = (maxValue - minValue)/2.0f; + if (value == NULL) value = &temp; + + float prevValue = *value; + + int sliderWidth = GuiGetStyle(SLIDER, SLIDER_WIDTH); + + Rectangle slider = { bounds.x, bounds.y + GuiGetStyle(SLIDER, BORDER_WIDTH) + GuiGetStyle(SLIDER, SLIDER_PADDING), + 0, bounds.height - 2*GuiGetStyle(SLIDER, BORDER_WIDTH) - 2*GuiGetStyle(SLIDER, SLIDER_PADDING) }; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (GUI_BUTTON_DOWN) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + state = STATE_PRESSED; + // Get equivalent value and slider position from mousePosition.x + *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width - sliderWidth)) + minValue; + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) + { + state = STATE_PRESSED; + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + + if (!CheckCollisionPointRec(mousePoint, slider)) + { + // Get equivalent value and slider position from mousePosition.x + *value = (maxValue - minValue)*((mousePoint.x - bounds.x - sliderWidth/2)/(bounds.width - sliderWidth)) + minValue; + } + } + else state = STATE_FOCUSED; + } + + if (*value > maxValue) *value = maxValue; + else if (*value < minValue) *value = minValue; + } + + // Slider bar limits check + float sliderValue = (((*value - minValue)/(maxValue - minValue))*(bounds.width - sliderWidth - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))); + if (sliderWidth > 0) // Slider + { + slider.x += sliderValue; + slider.width = (float)sliderWidth; + if (slider.x <= (bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH))) slider.x = bounds.x + GuiGetStyle(SLIDER, BORDER_WIDTH); + else if ((slider.x + slider.width) >= (bounds.x + bounds.width)) slider.x = bounds.x + bounds.width - slider.width - GuiGetStyle(SLIDER, BORDER_WIDTH); + } + else if (sliderWidth == 0) // SliderBar + { + slider.x += GuiGetStyle(SLIDER, BORDER_WIDTH); + slider.width = sliderValue; + if (slider.width > bounds.width) slider.width = bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH); + } + + if (prevValue != *value) result = RESULT_CHANGED; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(SLIDER, BORDER_WIDTH), GetColor(GuiGetStyle(SLIDER, BORDER + (state*3))), GetColor(GuiGetStyle(SLIDER, (state != STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED))); + + // Draw slider internal bar (depends on state) + if (state == STATE_NORMAL) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BASE_COLOR_PRESSED))); + else if (state == STATE_FOCUSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_FOCUSED))); + else if (state == STATE_PRESSED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_PRESSED))); + else if (state == STATE_DISABLED) GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, TEXT_COLOR_DISABLED))); + + // Draw left/right text if provided + if (textLeft != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GuiGetTextWidth(textLeft); + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x - textBounds.width - GuiGetStyle(SLIDER, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + } + + if (textRight != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GuiGetTextWidth(textRight); + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(SLIDER, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + } + //-------------------------------------------------------------------- + + return result; +} + +// Slider Bar control extended, returns selected value +int GuiSliderBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) +{ + int result = RESULT_NONE; + int preSliderWidth = GuiGetStyle(SLIDER, SLIDER_WIDTH); + GuiSetStyle(SLIDER, SLIDER_WIDTH, 0); + result = GuiSlider(bounds, textLeft, textRight, value, minValue, maxValue); + GuiSetStyle(SLIDER, SLIDER_WIDTH, preSliderWidth); + + return result; +} + +// Progress Bar control extended, shows current progress value +int GuiProgressBar(Rectangle bounds, const char *textLeft, const char *textRight, float *value, float minValue, float maxValue) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + float temp = (maxValue - minValue)/2.0f; + if (value == NULL) value = &temp; + float prevValue = *value; + + // Progress bar + Rectangle progress = { bounds.x + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), + bounds.y + GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) + GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING), 0, + bounds.height - GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - 2*GuiGetStyle(PROGRESSBAR, PROGRESS_PADDING) -1 }; + + // Update control + //-------------------------------------------------------------------- + if (*value > maxValue) *value = maxValue; + + // WARNING: Working with floats could lead to rounding issues + if ((state != STATE_DISABLED)) progress.width = ((float)*value/(maxValue - minValue))*(bounds.width - 2*GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)); + + if (prevValue != *value) result = RESULT_CHANGED; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state == STATE_DISABLED) + { + GuiDrawRectangle(bounds, GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), GetColor(GuiGetStyle(PROGRESSBAR, BORDER + (state*3))), BLANK); + } + else + { + if (*value > minValue) + { + // Draw progress bar with colored border, more visual + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height - 2 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); + } + else GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height+GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)-1 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); + + if (*value >= maxValue) GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height+GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)-1}, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_FOCUSED))); + else + { + // Draw borders not yet reached by value + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y, bounds.width - (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + (int)progress.width + (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y + bounds.height - 1, bounds.width - (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) - (int)progress.width - 1, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH) }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x + bounds.width - (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.y, (float)GuiGetStyle(PROGRESSBAR, BORDER_WIDTH), bounds.height+GuiGetStyle(PROGRESSBAR, BORDER_WIDTH)-1 }, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BORDER_COLOR_NORMAL))); + } + + // Draw slider internal progress bar (depends on state) + if (GuiGetStyle(PROGRESSBAR, PROGRESS_SIDE) == 0) // Left-->Right + { + GuiDrawRectangle(progress, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BASE_COLOR_PRESSED))); + } + else // Right-->Left + { + progress.x = bounds.x + bounds.width - progress.width - GuiGetStyle(PROGRESSBAR, BORDER_WIDTH); + GuiDrawRectangle(progress, 0, BLANK, GetColor(GuiGetStyle(PROGRESSBAR, BASE_COLOR_PRESSED))); + } + } + + // Draw left/right text if provided + if (textLeft != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GuiGetTextWidth(textLeft); + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x - textBounds.width - GuiGetStyle(PROGRESSBAR, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(textLeft, textBounds, TEXT_ALIGN_RIGHT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + } + + if (textRight != NULL) + { + Rectangle textBounds = { 0 }; + textBounds.width = (float)GuiGetTextWidth(textRight); + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + textBounds.x = bounds.x + bounds.width + GuiGetStyle(PROGRESSBAR, TEXT_PADDING); + textBounds.y = bounds.y + bounds.height/2 - GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + + GuiDrawText(textRight, textBounds, TEXT_ALIGN_LEFT, GetColor(GuiGetStyle(LABEL, TEXT + (state*3)))); + } + //-------------------------------------------------------------------- + + return result; +} + +// Status Bar control +int GuiStatusBar(Rectangle bounds, const char *text) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check checkbox state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + //if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + //else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(STATUSBAR, BORDER_WIDTH), GetColor(GuiGetStyle(STATUSBAR, BORDER + (state*3))), GetColor(GuiGetStyle(STATUSBAR, BASE + (state*3)))); + GuiDrawText(text, GetTextBounds(STATUSBAR, bounds), GuiGetStyle(STATUSBAR, TEXT_ALIGNMENT), GetColor(GuiGetStyle(STATUSBAR, TEXT + (state*3)))); + //-------------------------------------------------------------------- + + return result; +} + +// Dummy rectangle control, intended for placeholding +int GuiDummyRec(Rectangle bounds, const char *text) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check button state + if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) state = STATE_PRESSED; + else state = STATE_FOCUSED; + + if (GUI_BUTTON_RELEASED) result = RESULT_PRESSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, 0, BLANK, GetColor(GuiGetStyle(DEFAULT, (state != STATE_DISABLED)? BASE_COLOR_NORMAL : BASE_COLOR_DISABLED))); + GuiDrawText(text, GetTextBounds(DEFAULT, bounds), TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(BUTTON, (state != STATE_DISABLED)? TEXT_COLOR_NORMAL : TEXT_COLOR_DISABLED))); + //------------------------------------------------------------------ + + return result; +} + +// List View control +int GuiListView(Rectangle bounds, const char *text, int *scrollIndex, int *active) +{ + int result = RESULT_NONE; + int itemCount = 0; + char **items = NULL; + + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount); + + result = GuiListViewEx(bounds, items, itemCount, scrollIndex, active, NULL); + + return result; +} + +// List View control using text entries list and returning focus entry +int GuiListViewEx(Rectangle bounds, char **text, int count, int *scrollIndex, int *active, int *focus) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + int itemFocused = (focus == NULL)? -1 : *focus; + int itemSelected = (active == NULL)? -1 : *active; + int prevActive = (active == NULL)? 0 : *active; + + // Check if scroll bar is needed + bool useScrollBar = false; + if ((GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING))*count > bounds.height) useScrollBar = true; + + // Define base item rectangle [0] + Rectangle itemBounds = { 0 }; + itemBounds.x = bounds.x + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING); + itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); + itemBounds.width = bounds.width - 2*GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) - GuiGetStyle(DEFAULT, BORDER_WIDTH); + itemBounds.height = (float)GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT); + if (useScrollBar) itemBounds.width -= GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH); + + // Get items on the list + int visibleItems = (int)bounds.height/(GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING)); + if (visibleItems > count) visibleItems = count; + + int startIndex = (scrollIndex == NULL)? 0 : *scrollIndex; + if ((startIndex < 0) || (startIndex > (count - visibleItems))) startIndex = 0; + int endIndex = startIndex + visibleItems; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + // Check mouse inside list view + if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + + // Check focused and selected item + for (int i = 0; i < visibleItems; i++) + { + if (CheckCollisionPointRec(mousePoint, itemBounds)) + { + itemFocused = startIndex + i; + if (GUI_BUTTON_PRESSED) + { + if (itemSelected == (startIndex + i)) itemSelected = -1; + else itemSelected = startIndex + i; + } + break; + } + + // Update item rectangle y position for next item + itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING)); + } + + if (useScrollBar) + { + float scrollDelta = GUI_SCROLL_DELTA; + startIndex -= (int)scrollDelta; + + if (startIndex < 0) startIndex = 0; + else if (startIndex > (count - visibleItems)) startIndex = count - visibleItems; + + endIndex = startIndex + visibleItems; + if (endIndex > count) endIndex = count; + } + } + else itemFocused = -1; + + // Reset item rectangle y to [0] + itemBounds.y = bounds.y + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING) + GuiGetStyle(DEFAULT, BORDER_WIDTH); + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(LISTVIEW, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BACKGROUND_COLOR))); // Draw background + + // Draw visible items + for (int i = 0; ((i < visibleItems) && (text != NULL)); i++) + { + if (GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_NORMAL)) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_NORMAL)), BLANK); + + if (state == STATE_DISABLED) + { + if ((startIndex + i) == itemSelected) GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_DISABLED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_DISABLED))); + + GuiDrawText(text[startIndex + i], GetTextBounds(LISTVIEW, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_DISABLED))); + } + else + { + if (((startIndex + i) == itemSelected) && (active != NULL)) + { + // Draw item selected + GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_PRESSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_PRESSED))); + GuiDrawText(text[startIndex + i], GetTextBounds(LISTVIEW, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_PRESSED))); + } + else if (((startIndex + i) == itemFocused)) // && (focus != NULL)) // NOTE: Items focused, despite not returned + { + // Draw item focused + GuiDrawRectangle(itemBounds, GuiGetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER_COLOR_FOCUSED)), GetColor(GuiGetStyle(LISTVIEW, BASE_COLOR_FOCUSED))); + GuiDrawText(text[startIndex + i], GetTextBounds(LISTVIEW, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_FOCUSED))); + } + else + { + // Draw item normal (no rectangle) + GuiDrawText(text[startIndex + i], GetTextBounds(LISTVIEW, itemBounds), GuiGetStyle(LISTVIEW, TEXT_ALIGNMENT), GetColor(GuiGetStyle(LISTVIEW, TEXT_COLOR_NORMAL))); + } + } + + // Update item rectangle y position for next item + itemBounds.y += (GuiGetStyle(LISTVIEW, LIST_ITEMS_HEIGHT) + GuiGetStyle(LISTVIEW, LIST_ITEMS_SPACING)); + } + + if (useScrollBar) + { + Rectangle scrollBarBounds = { + bounds.x + bounds.width - GuiGetStyle(LISTVIEW, BORDER_WIDTH) - GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), + bounds.y + GuiGetStyle(LISTVIEW, BORDER_WIDTH), (float)GuiGetStyle(LISTVIEW, SCROLLBAR_WIDTH), + bounds.height - 2*GuiGetStyle(DEFAULT, BORDER_WIDTH) + }; + + // Calculate percentage of visible items and apply same percentage to scrollbar + float percentVisible = (float)(endIndex - startIndex)/count; + float sliderSize = bounds.height*percentVisible; + + int prevSliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); // Save default slider size + int prevScrollSpeed = GuiGetStyle(SCROLLBAR, SCROLL_SPEED); // Save default scroll speed + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, (int)sliderSize); // Change slider size + GuiSetStyle(SCROLLBAR, SCROLL_SPEED, count - visibleItems); // Change scroll speed + + startIndex = GuiScrollBar(scrollBarBounds, startIndex, 0, count - visibleItems); + + GuiSetStyle(SCROLLBAR, SCROLL_SPEED, prevScrollSpeed); // Reset scroll speed to default + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, prevSliderSize); // Reset slider size to default + } + //-------------------------------------------------------------------- + + if (active != NULL) *active = itemSelected; + if (focus != NULL) *focus = itemFocused; + if (scrollIndex != NULL) *scrollIndex = startIndex; + + if (prevActive != *active) result = RESULT_CHANGED; + + return result; +} + +// Tab Bar control +int GuiTabBar(Rectangle bounds, const char *text, int *hscroll, int *active) +{ + int result = RESULT_NONE; + int itemCount = 0; + char **items = NULL; + + if (text != NULL) items = GuiTextSplit(text, ';', &itemCount); + + result = GuiTabBarEx(bounds, items, itemCount, hscroll, active, NULL); + + return result; +} + +// Tab Bar control, using text entries list and returning focus entry +// NOTE: In case of tab close result, consider focused tab +// TODO: Reeplace GuiToggle() usage for custom implementation for the TABS +int GuiTabBarEx(Rectangle bounds, char **text, int count, int *hscroll, int *active, int *focus) +{ + int result = RESULT_NONE; + //GuiState state = guiState; + + int tabItemsWidth = GuiGetStyle(TABBAR, TAB_ITEMS_WIDTH); + Rectangle tabBounds = { bounds.x, bounds.y, (float)tabItemsWidth, bounds.height }; + + if (*active < 0) *active = 0; + else if (*active > count - 1) *active = count - 1; + + int prevActive = (active == NULL)? 0 : *active; + + int offsetX = 0; // Required in case tabs go out of screen + offsetX = (*active*tabItemsWidth) - GetScreenWidth(); + if (offsetX < 0) offsetX = 0; + + bool toggle = false; // Required for individual toggles + + // Draw control + //-------------------------------------------------------------------- + //if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) // TODO: Support disabled + + for (int i = 0; i < count; i++) + { + tabBounds.x = bounds.x + (tabItemsWidth + 4)*i + offsetX; + + if (tabBounds.x < GetScreenWidth()) + { + // Draw tabs as toggle controls + int textAlignment = GuiGetStyle(TOGGLE, TEXT_ALIGNMENT); + int textPadding = GuiGetStyle(TOGGLE, TEXT_PADDING); + GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(TOGGLE, TEXT_PADDING, 8); + + if (i == (*active)) + { + toggle = true; + GuiToggle(tabBounds, text[i], &toggle); + } + else + { + toggle = false; + GuiToggle(tabBounds, text[i], &toggle); + if (toggle) *active = i; + } + + // Close tab with middle mouse button pressed + if (CheckCollisionPointRec(GUI_POINTER_POSITION, tabBounds) && GUI_BUTTON_PRESSED_MID) result = RESULT_TAB_CLOSE; + + GuiSetStyle(TOGGLE, TEXT_PADDING, textPadding); + GuiSetStyle(TOGGLE, TEXT_ALIGNMENT, textAlignment); + + if (GuiGetStyle(TABBAR, TAB_CLOSE_BUTTON)) + { + // Draw tab close button + // NOTE: Only draw close button for current tab: if (CheckCollisionPointRec(mousePosition, tabBounds)) + int tempBorderWidth = GuiGetStyle(BUTTON, BORDER_WIDTH); + int tempTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 1); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); +#if defined(RAYGUI_NO_ICONS) + if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, "x")) result = RESULT_TAB_CLOSE; +#else + if (GuiButton(RAYGUI_CLITERAL(Rectangle){ tabBounds.x + tabBounds.width - 14 - 5, tabBounds.y + 5, 14, 14 }, + GuiIconText(ICON_CROSS_SMALL, NULL))) result = RESULT_TAB_CLOSE; +#endif + GuiSetStyle(BUTTON, BORDER_WIDTH, tempBorderWidth); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, tempTextAlignment); + } + } + } + + // Draw tab-bar bottom line + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + bounds.height - 1, bounds.width, 1 }, 0, BLANK, GetColor(GuiGetStyle(TABBAR, BORDER_COLOR_NORMAL))); + //-------------------------------------------------------------------- + + // NOTE: In case of tab close result, consider focused tab + if ((result != RESULT_TAB_CLOSE) && (prevActive != *active)) result = RESULT_CHANGED; + + return result; +} + +// Color Panel control +int GuiColorPanel(Rectangle bounds, const char *text, Color *color) +{ + int result = RESULT_NONE; + + Vector3 vcolor = { (float)color->r/255.0f, (float)color->g/255.0f, (float)color->b/255.0f }; + Vector3 hsv = ConvertRGBtoHSV(vcolor); + Vector3 prevHsv = hsv; // NOTE: Workaround to see if GuiColorPanelHSV() modifies the hsv + + result = GuiColorPanelHSV(bounds, text, &hsv); + + // Check if the hsv was changed, only then change the color + // This is required, because the Color->HSV->Color conversion has precision errors + // Thus the assignment from HSV to Color should only be made, if the HSV has a new user-entered value + // Otherwise GuiColorPanel would often modify it's color without user input + if ((hsv.x != prevHsv.x) || (hsv.y != prevHsv.y) || (hsv.z != prevHsv.z)) + { + Vector3 rgb = ConvertHSVtoRGB(hsv); + *color = RAYGUI_CLITERAL(Color){ (unsigned char)(255.0f*rgb.x), (unsigned char)(255.0f*rgb.y), (unsigned char)(255.0f*rgb.z), color->a }; + } + + return result; +} + +// Color Bar Alpha control +// NOTE: Returns alpha value normalized [0..1] +int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) +{ + #if !defined(RAYGUI_COLORBARALPHA_CHECKED_SIZE) + #define RAYGUI_COLORBARALPHA_CHECKED_SIZE 10 + #endif + + int result = RESULT_NONE; + GuiState state = guiState; + + float prevAlpha = *alpha; + Rectangle selector = { (float)bounds.x + (*alpha)*bounds.width - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, + (float)bounds.y - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), + (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT), + (float)bounds.height + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2 }; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (GUI_BUTTON_DOWN) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + state = STATE_PRESSED; + + *alpha = (mousePoint.x - bounds.x)/bounds.width; + if (*alpha <= 0.0f) *alpha = 0.0f; + if (*alpha >= 1.0f) *alpha = 1.0f; + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) + { + if (GUI_BUTTON_DOWN) + { + state = STATE_PRESSED; + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + + *alpha = (mousePoint.x - bounds.x)/bounds.width; + if (*alpha <= 0.0f) *alpha = 0.0f; + if (*alpha >= 1.0f) *alpha = 1.0f; + //selector.x = bounds.x + (int)(((alpha - 0)/(100 - 0))*(bounds.width - 2*GuiGetStyle(SLIDER, BORDER_WIDTH))) - selector.width/2; + } + else state = STATE_FOCUSED; + } + } + + if (prevAlpha != *alpha) result = RESULT_CHANGED; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + // Draw alpha bar: checked background + if (state != STATE_DISABLED) + { + int checksX = (int)bounds.width/RAYGUI_COLORBARALPHA_CHECKED_SIZE; + int checksY = (int)bounds.height/RAYGUI_COLORBARALPHA_CHECKED_SIZE; + + for (int x = 0; x < checksX; x++) + { + for (int y = 0; y < checksY; y++) + { + Rectangle check = { bounds.x + x*RAYGUI_COLORBARALPHA_CHECKED_SIZE, bounds.y + y*RAYGUI_COLORBARALPHA_CHECKED_SIZE, RAYGUI_COLORBARALPHA_CHECKED_SIZE, RAYGUI_COLORBARALPHA_CHECKED_SIZE }; + GuiDrawRectangle(check, 0, BLANK, ((x + y)%2)? Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.4f) : Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.4f)); + } + } + + DrawRectangleGradientEx(bounds, RAYGUI_CLITERAL(Color){ 255, 255, 255, 0 }, RAYGUI_CLITERAL(Color){ 255, 255, 255, 0 }, Fade(RAYGUI_CLITERAL(Color){ 0, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 0, 255 }, guiAlpha)); + } + else DrawRectangleGradientEx(bounds, Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha)); + + GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); + + // Draw alpha bar: selector + GuiDrawRectangle(selector, 0, BLANK, GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3))); + //-------------------------------------------------------------------- + + return result; +} + +// Color Bar Hue control +// Returns hue value normalized [0..1] +// NOTE: Other similar bars (for reference): +// Color GuiColorBarSat() [WHITE->color] +// Color GuiColorBarValue() [BLACK->color], HSV/HSL +// float GuiColorBarLuminance() [BLACK->WHITE] +int GuiColorBarHue(Rectangle bounds, const char *text, float *hue) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + float prevHue = *hue; + Rectangle selector = { (float)bounds.x - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW), (float)bounds.y + (*hue)/360.0f*bounds.height - GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT)/2, (float)bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW)*2, (float)GuiGetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT) }; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (GUI_BUTTON_DOWN) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + state = STATE_PRESSED; + + *hue = (mousePoint.y - bounds.y)*360/bounds.height; + if (*hue <= 0.0f) *hue = 0.0f; + if (*hue >= 359.0f) *hue = 359.0f; + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds) || CheckCollisionPointRec(mousePoint, selector)) + { + if (GUI_BUTTON_DOWN) + { + state = STATE_PRESSED; + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + + *hue = (mousePoint.y - bounds.y)*360/bounds.height; + if (*hue <= 0.0f) *hue = 0.0f; + if (*hue >= 359.0f) *hue = 359.0f; + + } + else state = STATE_FOCUSED; + + /*if (GUI_KEY_DOWN(KEY_UP)) + { + hue -= 2.0f; + if (hue <= 0.0f) hue = 0.0f; + } + else if (GUI_KEY_DOWN(KEY_DOWN)) + { + hue += 2.0f; + if (hue >= 360.0f) hue = 360.0f; + }*/ + } + } + + if (prevHue != *hue) result = RESULT_CHANGED; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state != STATE_DISABLED) + { + // Draw hue bar:color bars + // NOTE: Using DrawRectangleGradientEx(bounds, color1, color2, color2, color1); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y, bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 1*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 255, 0, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 2*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 0, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 3*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 255, 255, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 4*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 0, 0, 255, 255 }, guiAlpha)); + DrawRectangleGradientEx(RAYGUI_CLITERAL(Rectangle){ bounds.x, bounds.y + 5*(bounds.height/6.0f), bounds.width, bounds.height/6.0f }, + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), + Fade(RAYGUI_CLITERAL(Color){ 255, 0, 0, 255 }, guiAlpha), Fade(RAYGUI_CLITERAL(Color){ 255, 0, 255, 255 }, guiAlpha)); + } + else + { + DrawRectangleGradientEx(bounds, + Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), + Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), guiAlpha), Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha)); + } + + GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); + + // Draw hue bar: selector + GuiDrawRectangle(selector, 0, BLANK, GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3))); + //-------------------------------------------------------------------- + + return result; +} + +// Color Picker control +// NOTE: It's divided in multiple controls: +// Color GuiColorPanel(Rectangle bounds, Color color) +// float GuiColorBarAlpha(Rectangle bounds, float alpha) +// float GuiColorBarHue(Rectangle bounds, float value) +// NOTE: bounds define GuiColorPanel() size +// NOTE: this picker converts RGB to HSV, which can cause the Hue control to jump. If you have this problem, consider using the HSV variant instead +int GuiColorPicker(Rectangle bounds, const char *text, Color *color) +{ + int result = RESULT_NONE; + + Color temp = { 200, 0, 0, 255 }; + if (color == NULL) color = &temp; + + result = GuiColorPanel(bounds, NULL, color); + + Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; + //Rectangle boundsAlpha = { bounds.x, bounds.y + bounds.height + GuiGetStyle(COLORPICKER, BARS_PADDING), bounds.width, GuiGetStyle(COLORPICKER, BARS_THICK) }; + + // NOTE: this conversion can cause low hue-resolution, if the r, g and b value are very similar, which causes the hue bar to shift around when only the GuiColorPanel is used + Vector3 hsv = ConvertRGBtoHSV(RAYGUI_CLITERAL(Vector3){ (*color).r/255.0f, (*color).g/255.0f, (*color).b/255.0f }); + + if (result != RESULT_CHANGED) result = GuiColorBarHue(boundsHue, NULL, &hsv.x); + + //color.a = (unsigned char)(GuiColorBarAlpha(boundsAlpha, (float)color.a/255.0f)*255.0f); + Vector3 rgb = ConvertHSVtoRGB(hsv); + + *color = RAYGUI_CLITERAL(Color){ (unsigned char)roundf(rgb.x*255.0f), (unsigned char)roundf(rgb.y*255.0f), (unsigned char)roundf(rgb.z*255.0f), (*color).a }; + + return result; +} + +// Color Picker control that avoids conversion to RGB and back to HSV on each call, thus avoiding jittering +// The user can call ConvertHSVtoRGB() to convert *colorHsv value to RGB +// NOTE: It's divided in multiple controls: +// int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) +// int GuiColorBarAlpha(Rectangle bounds, const char *text, float *alpha) +// float GuiColorBarHue(Rectangle bounds, float value) +// NOTE: bounds define GuiColorPanelHSV() size +int GuiColorPickerHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) +{ + int result = RESULT_NONE; + + Vector3 tempHsv = { 0 }; + + if (colorHsv == NULL) + { + const Vector3 tempColor = { 200.0f/255.0f, 0.0f, 0.0f }; + tempHsv = ConvertRGBtoHSV(tempColor); + colorHsv = &tempHsv; + } + + result = GuiColorPanelHSV(bounds, NULL, colorHsv); + + Rectangle boundsHue = { (float)bounds.x + bounds.width + GuiGetStyle(COLORPICKER, HUEBAR_PADDING), (float)bounds.y, (float)GuiGetStyle(COLORPICKER, HUEBAR_WIDTH), (float)bounds.height }; + + if (result == RESULT_NONE) result = GuiColorBarHue(boundsHue, NULL, &colorHsv->x); + + return result; +} + +// Color Panel control - HSV variant +int GuiColorPanelHSV(Rectangle bounds, const char *text, Vector3 *colorHsv) +{ + int result = RESULT_NONE; + GuiState state = guiState; + + Vector3 prevColorHsv = *colorHsv; + Vector2 pickerSelector = { 0 }; + const Color colWhite = { 255, 255, 255, 255 }; + const Color colBlack = { 0, 0, 0, 255 }; + + pickerSelector.x = bounds.x + (float)colorHsv->y*bounds.width; // HSV: Saturation + pickerSelector.y = bounds.y + (1.0f - (float)colorHsv->z)*bounds.height; // HSV: Value + + Vector3 maxHue = { colorHsv->x, 1.0f, 1.0f }; + Vector3 rgbHue = ConvertHSVtoRGB(maxHue); + Color maxHueCol = { (unsigned char)(255.0f*rgbHue.x), (unsigned char)(255.0f*rgbHue.y), (unsigned char)(255.0f*rgbHue.z), 255 }; + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (GUI_BUTTON_DOWN) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + pickerSelector = mousePoint; + + if (pickerSelector.x < bounds.x) pickerSelector.x = bounds.x; + if (pickerSelector.x > bounds.x + bounds.width) pickerSelector.x = bounds.x + bounds.width; + if (pickerSelector.y < bounds.y) pickerSelector.y = bounds.y; + if (pickerSelector.y > bounds.y + bounds.height) pickerSelector.y = bounds.y + bounds.height; + + // Calculate color from picker + Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y }; + + colorPick.x /= (float)bounds.width; // Get normalized value on x + colorPick.y /= (float)bounds.height; // Get normalized value on y + + colorHsv->y = colorPick.x; + colorHsv->z = 1.0f - colorPick.y; + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds)) + { + if (GUI_BUTTON_DOWN) + { + state = STATE_PRESSED; + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; + pickerSelector = mousePoint; + + // Calculate color from picker + Vector2 colorPick = { pickerSelector.x - bounds.x, pickerSelector.y - bounds.y }; + + colorPick.x /= (float)bounds.width; // Get normalized value on x + colorPick.y /= (float)bounds.height; // Get normalized value on y + + colorHsv->y = colorPick.x; + colorHsv->z = 1.0f - colorPick.y; + } + else state = STATE_FOCUSED; + } + } + + if ((prevColorHsv.x != colorHsv->x) || + (prevColorHsv.y != colorHsv->y) || + (prevColorHsv.z != colorHsv->z)) result = RESULT_CHANGED; + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state != STATE_DISABLED) + { + DrawRectangleGradientEx(bounds, Fade(colWhite, guiAlpha), Fade(colWhite, guiAlpha), Fade(maxHueCol, guiAlpha), Fade(maxHueCol, guiAlpha)); + DrawRectangleGradientEx(bounds, Fade(colBlack, 0), Fade(colBlack, guiAlpha), Fade(colBlack, guiAlpha), Fade(colBlack, 0)); + + // Draw color picker: selector + Rectangle selector = { pickerSelector.x - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, pickerSelector.y - GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE)/2, (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE), (float)GuiGetStyle(COLORPICKER, COLOR_SELECTOR_SIZE) }; + GuiDrawRectangle(selector, 0, BLANK, colWhite); + } + else + { + DrawRectangleGradientEx(bounds, Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BASE_COLOR_DISABLED)), 0.1f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(colBlack, 0.6f), guiAlpha), Fade(Fade(GetColor(GuiGetStyle(COLORPICKER, BORDER_COLOR_DISABLED)), 0.6f), guiAlpha)); + } + + GuiDrawRectangle(bounds, GuiGetStyle(COLORPICKER, BORDER_WIDTH), GetColor(GuiGetStyle(COLORPICKER, BORDER + state*3)), BLANK); + //-------------------------------------------------------------------- + + return result; +} + +// Message Box control +// NOTE: Button pressed is returned through btnActive parameter, 0 for window close button +int GuiMessageBox(Rectangle bounds, const char *title, const char *message, const char *btnText, int *btnActive) +{ + #if !defined(RAYGUI_MESSAGEBOX_BUTTON_HEIGHT) + #define RAYGUI_MESSAGEBOX_BUTTON_HEIGHT 24 + #endif + #if !defined(RAYGUI_MESSAGEBOX_BUTTON_PADDING) + #define RAYGUI_MESSAGEBOX_BUTTON_PADDING 12 + #endif + + int result = RESULT_NONE; + + int buttonCount = 0; + char **btnTextList = GuiTextSplit(btnText, ';', &buttonCount); + Rectangle buttonBounds = { 0 }; + buttonBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING; + buttonBounds.y = bounds.y + bounds.height - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT - RAYGUI_MESSAGEBOX_BUTTON_PADDING; + buttonBounds.width = (bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount; + buttonBounds.height = RAYGUI_MESSAGEBOX_BUTTON_HEIGHT; + + //int textWidth = GuiGetTextWidth(message) + 2; + + Rectangle textBounds = { 0 }; + textBounds.x = bounds.x + RAYGUI_MESSAGEBOX_BUTTON_PADDING; + textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + RAYGUI_MESSAGEBOX_BUTTON_PADDING; + textBounds.width = bounds.width - RAYGUI_MESSAGEBOX_BUTTON_PADDING*2; + textBounds.height = bounds.height - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - 3*RAYGUI_MESSAGEBOX_BUTTON_PADDING - RAYGUI_MESSAGEBOX_BUTTON_HEIGHT; + + // Draw control + //-------------------------------------------------------------------- + if (GuiWindowBox(bounds, title) == RESULT_PRESSED) + { + *btnActive = 0; + result = RESULT_PRESSED; + } + + int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + GuiLabel(textBounds, message); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment); + + prevTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + + for (int i = 0; i < buttonCount; i++) + { + if (GuiButton(buttonBounds, btnTextList[i])) + { + *btnActive = i + 1; + result = RESULT_PRESSED; + } + buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING); + } + + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevTextAlignment); + //-------------------------------------------------------------------- + + return result; +} + +// Text Input Box control +// NOTE: Button pressed is returned through btnActive parameter, 0 for window close button +int GuiTextInputBox(Rectangle bounds, const char *title, const char *message, char *text, int textSize, const char *btnText, int *btnActive, bool *secretViewActive) +{ + #if !defined(RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT) + #define RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT 24 + #endif + #if !defined(RAYGUI_TEXTINPUTBOX_BUTTON_PADDING) + #define RAYGUI_TEXTINPUTBOX_BUTTON_PADDING 12 + #endif + #if !defined(RAYGUI_TEXTINPUTBOX_HEIGHT) + #define RAYGUI_TEXTINPUTBOX_HEIGHT 26 + #endif + + int result = RESULT_NONE; + + // Used to enable text edit mode + // WARNING: No more than one GuiTextInputBox() should be open at the same time + static bool textEditMode = false; + + int buttonCount = 0; + char **btnTextList = GuiTextSplit(btnText, ';', &buttonCount); + Rectangle buttonBounds = { 0 }; + buttonBounds.x = bounds.x + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; + buttonBounds.y = bounds.y + bounds.height - RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; + buttonBounds.width = (bounds.width - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING*(buttonCount + 1))/buttonCount; + buttonBounds.height = RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT; + + int messageInputHeight = (int)bounds.height - RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - GuiGetStyle(STATUSBAR, BORDER_WIDTH) - RAYGUI_TEXTINPUTBOX_BUTTON_HEIGHT - 2*RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; + + Rectangle textBounds = { 0 }; + if (message != NULL) + { + int textSize = GuiGetTextWidth(message) + 2; + + textBounds.x = bounds.x + bounds.width/2 - textSize/2; + textBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT + messageInputHeight/4 - (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/2; + textBounds.width = (float)textSize; + textBounds.height = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + } + + Rectangle textBoxBounds = { 0 }; + textBoxBounds.x = bounds.x + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; + textBoxBounds.y = bounds.y + RAYGUI_WINDOWBOX_STATUSBAR_HEIGHT - RAYGUI_TEXTINPUTBOX_HEIGHT/2; + if (message == NULL) textBoxBounds.y = bounds.y + 24 + RAYGUI_TEXTINPUTBOX_BUTTON_PADDING; + else textBoxBounds.y += (messageInputHeight/2 + messageInputHeight/4); + textBoxBounds.width = bounds.width - RAYGUI_TEXTINPUTBOX_BUTTON_PADDING*2; + textBoxBounds.height = RAYGUI_TEXTINPUTBOX_HEIGHT; + + // Draw control + //-------------------------------------------------------------------- + if (GuiWindowBox(bounds, title) == RESULT_PRESSED) + { + *btnActive = 0; + result = RESULT_PRESSED; + } + + // Draw message if available + if (message != NULL) + { + int prevTextAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + GuiLabel(textBounds, message); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, prevTextAlignment); + } + + int prevTextBoxAlignment = GuiGetStyle(TEXTBOX, TEXT_ALIGNMENT); + GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + + if (secretViewActive != NULL) + { + static char stars[] = "****************"; + if (GuiTextBox(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x, textBoxBounds.y, textBoxBounds.width - 4 - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.height }, + ((*secretViewActive == 1) || textEditMode)? text : stars, textSize, textEditMode) == RESULT_PRESSED) textEditMode = !textEditMode; + +#if defined(RAYGUI_NO_ICONS) + GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, + (*secretViewActive == 1)? "O" : "*", secretViewActive); +#else + GuiToggle(RAYGUI_CLITERAL(Rectangle){ textBoxBounds.x + textBoxBounds.width - RAYGUI_TEXTINPUTBOX_HEIGHT, textBoxBounds.y, RAYGUI_TEXTINPUTBOX_HEIGHT, RAYGUI_TEXTINPUTBOX_HEIGHT }, + (*secretViewActive == 1)? GuiIconText(ICON_EYE_ON, NULL) : GuiIconText(ICON_EYE_OFF, NULL), secretViewActive); +#endif + } + else + { + if (GuiTextBox(textBoxBounds, text, textSize, textEditMode) == RESULT_PRESSED) + textEditMode = !textEditMode; + } + + GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, prevTextBoxAlignment); + + int prevBtnTextAlignment = GuiGetStyle(BUTTON, TEXT_ALIGNMENT); + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + + for (int i = 0; i < buttonCount; i++) + { + if (GuiButton(buttonBounds, btnTextList[i])) + { + *btnActive = i + 1; + result = RESULT_PRESSED; + } + + buttonBounds.x += (buttonBounds.width + RAYGUI_MESSAGEBOX_BUTTON_PADDING); + } + + if (result == RESULT_PRESSED) textEditMode = false; + + GuiSetStyle(BUTTON, TEXT_ALIGNMENT, prevBtnTextAlignment); + //-------------------------------------------------------------------- + + return result; +} + +// Grid control +// NOTE: Returns grid mouse-hover selected cell +// About drawing lines at subpixel spacing, simple put, not easy solution: +// REF: https://stackoverflow.com/questions/4435450/2d-opengl-drawing-lines-that-dont-exactly-fit-pixel-raster +int GuiGrid(Rectangle bounds, const char *text, float spacing, int subdivs, Vector2 *mouseCell) +{ + // Grid lines alpha amount + #if !defined(RAYGUI_GRID_ALPHA) + #define RAYGUI_GRID_ALPHA 0.15f + #endif + + int result = RESULT_NONE; + GuiState state = guiState; + + Vector2 mousePoint = GUI_POINTER_POSITION; + Vector2 currentMouseCell = { -1, -1 }; + + float spaceWidth = spacing/(float)subdivs; + int linesV = (int)(bounds.width/spaceWidth) + 1; + int linesH = (int)(bounds.height/spaceWidth) + 1; + + int color = GuiGetStyle(DEFAULT, LINE_COLOR); + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked && !guiControlExclusiveMode) + { + if (CheckCollisionPointRec(mousePoint, bounds)) + { + // NOTE: Cell values must be the upper left of the cell the mouse is in + currentMouseCell.x = floorf((mousePoint.x - bounds.x)/spacing); + currentMouseCell.y = floorf((mousePoint.y - bounds.y)/spacing); + + result = RESULT_PRESSED; + } + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + if (state == STATE_DISABLED) color = GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED); + + if (subdivs > 0) + { + // Draw vertical grid lines + for (int i = 0; i < linesV; i++) + { + Rectangle lineV = { bounds.x + spacing*i/subdivs, bounds.y, 1, bounds.height + 1 }; + GuiDrawRectangle(lineV, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(color), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(color), RAYGUI_GRID_ALPHA)); + } + + // Draw horizontal grid lines + for (int i = 0; i < linesH; i++) + { + Rectangle lineH = { bounds.x, bounds.y + spacing*i/subdivs, bounds.width + 1, 1 }; + GuiDrawRectangle(lineH, 0, BLANK, ((i%subdivs) == 0)? GuiFade(GetColor(color), RAYGUI_GRID_ALPHA*4) : GuiFade(GetColor(color), RAYGUI_GRID_ALPHA)); + } + } + + if (mouseCell != NULL) *mouseCell = currentMouseCell; + + return result; +} + +//---------------------------------------------------------------------------------- +// Tooltip management functions +// NOTE: Tooltips requires some global variables: tooltipPtr +//---------------------------------------------------------------------------------- +// Enable gui tooltips (global state) +void GuiEnableTooltip(void) { guiTooltip = true; } + +// Disable gui tooltips (global state) +void GuiDisableTooltip(void) { guiTooltip = false; } + +// Set tooltip string +void GuiSetTooltip(const char *tooltip) { guiTooltipPtr = tooltip; } + +//---------------------------------------------------------------------------------- +// Styles loading functions +//---------------------------------------------------------------------------------- + +// Load raygui style file (.rgs) +// NOTE: By default a binary file is expected, that file could contain a custom font, +// in that case, custom font image atlas is GRAY+ALPHA and pixel data can be compressed (DEFLATE) +void GuiLoadStyle(const char *fileName) +{ + #define MAX_LINE_BUFFER_SIZE 256 + + bool tryBinary = false; + if (!guiStyleLoaded) GuiLoadStyleDefault(); + + // Try reading the files as text file first + FILE *rgsFile = fopen(fileName, "rt"); + + if (rgsFile != NULL) + { + char buffer[MAX_LINE_BUFFER_SIZE] = { 0 }; + fgets(buffer, MAX_LINE_BUFFER_SIZE, rgsFile); + + if (buffer[0] == '#') + { + int controlId = 0; + int propertyId = 0; + unsigned int propertyValue = 0; + unsigned int version = 0; + + while (!feof(rgsFile)) + { + switch (buffer[0]) + { + case 'v': + { + sscanf(buffer, "v %d", &version); + } + case 'p': + { + // Style property: p + + sscanf(buffer, "p %d %d 0x%x", &controlId, &propertyId, &propertyValue); + GuiSetStyle(controlId, propertyId, (int)propertyValue); + + } break; + case 'f': + { + // Style font: f + + int fontSize = 0; + char charmapFileName[32] = { 0 }; + char fontFileName[32] = { 0 }; + + if (version >= 600) sscanf(buffer, "f %d %31s %31[^\r\n]s", &fontSize, fontFileName, charmapFileName); + else sscanf(buffer, "f %d %31s %31[^\r\n]s", &fontSize, charmapFileName, fontFileName); + + // GLOBAL: Copy font file name into guiFontName + snprintf(guiFontName, 32, "%s", fontFileName); + + Font font = { 0 }; + int *codepoints = NULL; + int codepointCount = 0; + + if (charmapFileName[0] != '0') + { + // Load text data from file + // NOTE: Expected an UTF-8 array of codepoints, no separation + char *textData = LoadFileText(TextFormat("%s/%s", GetDirectoryPath(fileName), charmapFileName)); + codepoints = LoadCodepoints(textData, &codepointCount); + UnloadFileText(textData); + } + + if (fontFileName[0] != '\0') + { + // In case a font is already loaded and it is not default internal font, unload it + if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture); + + if (codepointCount > 0) font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, codepoints, codepointCount); + else font = LoadFontEx(TextFormat("%s/%s", GetDirectoryPath(fileName), fontFileName), fontSize, NULL, 0); // Default to 95 standard codepoints + } + + // If font texture not properly loaded, revert to default font and size/spacing + if (font.texture.id == 0) + { + font = GetFontDefault(); + GuiSetStyle(DEFAULT, TEXT_SIZE, 10); + GuiSetStyle(DEFAULT, TEXT_SPACING, 1); + } + + UnloadCodepoints(codepoints); + + if ((font.texture.id > 0) && (font.glyphCount > 0)) GuiSetFont(font); + + } break; + default: break; + } + + fgets(buffer, MAX_LINE_BUFFER_SIZE, rgsFile); + } + } + else tryBinary = true; + + fclose(rgsFile); + } + + if (tryBinary) + { + rgsFile = fopen(fileName, "rb"); + + if (rgsFile != NULL) + { + fseek(rgsFile, 0, SEEK_END); + int fileDataSize = ftell(rgsFile); + fseek(rgsFile, 0, SEEK_SET); + + if (fileDataSize > 0) + { + unsigned char *fileData = (unsigned char *)RAYGUI_CALLOC(fileDataSize, sizeof(unsigned char)); + if (fileData != NULL) + { + fread(fileData, sizeof(unsigned char), fileDataSize, rgsFile); + + GuiLoadStyleFromMemory(fileData, fileDataSize); + + RAYGUI_FREE(fileData); + } + } + + fclose(rgsFile); + } + } +} + +// Load style from memory +// WARNING: Binary files only +void GuiLoadStyleFromMemory(const unsigned char *fileData, int dataSize) +{ + // Style File Structure (.rgs) + // ------------------------------------------------------ + // Offset | Size | Type | Description + // ------------------------------------------------------ + // 0 | 4 | char | Signature: "rGS " + // 4 | 2 | short | Version: 200, 400, 600 + // 6 | 2 | short | reserved + // 8 | 4 | int | Num properties (only changed ones from default style) + + // Properties Data (8 bytes per property) + // WARNING: Only properties required that differ from default (light) internal style + // foreach (property) + // { + // 8+8*i | 2 | short | ControlId + // 8+8*i | 2 | short | PropertyId + // 8+8*i | 4 | int | PropertyValue + // } + + // Custom Font Data : Parameters (64 bytes) + // ... | 4 | int | Font data size (0 - no font, no more fields added!) + // ... | 32 | char | Font filename (with extension) - VERSION: >=600 + // ... | 4 | int | Font base size + // ... | 4 | int | Font glyph count [glyphCount] + // ... | 4 | int | Font type (0-NORMAL, 1-SDF) + // ... | 16 | Rectangle | Font white rectangle + + // Custom Font Data : Image (20 bytes + imData) + // NOTE: Font image atlas is always converted to GRAY+ALPHA + // and atlas image data can be compressed (DEFLATE) + // ... | 4 | int | Image data size (uncompressed) + // ... | 4 | int | Image data size (compressed) + // ... | 4 | int | Image width + // ... | 4 | int | Image height + // ... | 4 | int | Image format: GRAY+ALPHA (expected) + // ... | imSize | byte | Image data (comp or uncomp) + + // Custom Font Data : Recs (32 bytes*glyphCount) + // NOTE: Font recs data can be compressed (DEFLATE) + // ... | 4 | int | Recs data compressed size (0 - not compressed, 1-compressed) - VERSION: >=400 + // + // if (compRecsSize == 0) + // { + // NOTE: Uncompressed size can be calculated: (glyphCount*16 byte) + // foreach (glyph) + // { + // ... | 16 | Rectangle | Glyph rectangle (in image) + // } + // } + // else + // { + // ... | compRecsSize | byte | Rectangles data + // } + // + + // Custom Font Data : Glyph Info (32 bytes*glyphCount) + // NOTE: Font glyphs info data can be compressed (DEFLATE) + // ... | 4 | int | Glyphs data compressed size (0 - not compressed) - VERSION: >=400 + // + // if (compGlyphsSize == 0) + // { + // NOTE: Uncompressed size can be calculated: (glyphCount*16 byte) + // foreach (glyph) + // { + // ... | 4 | int | Glyph value + // ... | 4 | int | Glyph offset X + // ... | 4 | int | Glyph offset Y + // ... | 4 | int | Glyph advance X + // } + // } + // else + // { + // ... | compGlyphsSize | byte | Glyphs data + // } + // ------------------------------------------------------ + + unsigned char *fileDataPtr = (unsigned char *)fileData; + + char signature[5] = { 0 }; + short version = 0; + short reserved = 0; + int propertyCount = 0; + + memcpy(signature, fileDataPtr, 4); + memcpy(&version, fileDataPtr + 4, sizeof(short)); + memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short)); + memcpy(&propertyCount, fileDataPtr + 4 + 2 + 2, sizeof(int)); + fileDataPtr += 12; + + if ((signature[0] == 'r') && + (signature[1] == 'G') && + (signature[2] == 'S') && + (signature[3] == ' ')) + { + short controlId = 0; + short propertyId = 0; + unsigned int propertyValue = 0; + + for (int i = 0; i < propertyCount; i++) + { + memcpy(&controlId, fileDataPtr, sizeof(short)); + memcpy(&propertyId, fileDataPtr + 2, sizeof(short)); + memcpy(&propertyValue, fileDataPtr + 2 + 2, sizeof(unsigned int)); + fileDataPtr += 8; + + if (controlId == 0) // DEFAULT control + { + // If a DEFAULT property is loaded, it is propagated to all controls + // NOTE: All DEFAULT properties should be defined first in the file + GuiSetStyle(0, (int)propertyId, propertyValue); + + if (propertyId < RAYGUI_MAX_PROPS_BASE) for (int j = 1; j < RAYGUI_MAX_CONTROLS; j++) GuiSetStyle(j, (int)propertyId, propertyValue); + } + else GuiSetStyle((int)controlId, (int)propertyId, propertyValue); + } + + // Load custom font if available + // NOTE: Font texture loading requires raylib + int fontDataSize = 0; + memcpy(&fontDataSize, fileDataPtr, sizeof(int)); + fileDataPtr += 4; + + if (fontDataSize > 0) + { + Font font = { 0 }; + int fontType = 0; // 0-Normal, 1-SDF + + // WARNING: Version 600 adds 32 bytes for the font filename (with extension) + if (version >= 600) + { + // GLOBAL: Copy font file name into guiFontName + memcpy(guiFontName, fileDataPtr, 32); + fileDataPtr += 32; + } + else memset(guiFontName, 0, 32); + + memcpy(&font.baseSize, fileDataPtr, sizeof(int)); + memcpy(&font.glyphCount, fileDataPtr + 4, sizeof(int)); + memcpy(&fontType, fileDataPtr + 4 + 4, sizeof(int)); + fileDataPtr += 12; + + // Load font white rectangle + Rectangle fontWhiteRec = { 0 }; + memcpy(&fontWhiteRec, fileDataPtr, sizeof(Rectangle)); + fileDataPtr += 16; + + // Load font image parameters + int fontImageUncompSize = 0; + int fontImageCompSize = 0; + memcpy(&fontImageUncompSize, fileDataPtr, sizeof(int)); + memcpy(&fontImageCompSize, fileDataPtr + 4, sizeof(int)); + fileDataPtr += 8; + + Image imFont = { 0 }; + imFont.mipmaps = 1; + memcpy(&imFont.width, fileDataPtr, sizeof(int)); + memcpy(&imFont.height, fileDataPtr + 4, sizeof(int)); + memcpy(&imFont.format, fileDataPtr + 4 + 4, sizeof(int)); + fileDataPtr += 12; + + if ((fontImageCompSize > 0) && (fontImageCompSize != fontImageUncompSize)) + { + // Compressed font atlas image data (DEFLATE), it requires DecompressData() + int dataUncompSize = 0; + unsigned char *compData = (unsigned char *)RAYGUI_CALLOC(fontImageCompSize, sizeof(unsigned char)); + memcpy(compData, fileDataPtr, fontImageCompSize); + fileDataPtr += fontImageCompSize; + + imFont.data = DecompressData(compData, fontImageCompSize, &dataUncompSize); + + // Security check, dataUncompSize must match the provided fontImageUncompSize + if (dataUncompSize != fontImageUncompSize) RAYGUI_LOG("WARNING: Uncompressed font atlas image data could be corrupted"); + + RAYGUI_FREE(compData); + } + else + { + // Font atlas image data is not compressed + imFont.data = (unsigned char *)RAYGUI_CALLOC(fontImageUncompSize, sizeof(unsigned char)); + memcpy(imFont.data, fileDataPtr, fontImageUncompSize); + fileDataPtr += fontImageUncompSize; + } + + // Load font recs data (glyphs position and size in the image atlas) + int recsDataSize = font.glyphCount*sizeof(Rectangle); + int recsDataCompressedSize = 0; + + // WARNING: Version 400 adds the compression size parameter + if (version >= 400) + { + // RGS files version 400 support compressed recs data + memcpy(&recsDataCompressedSize, fileDataPtr, sizeof(int)); + fileDataPtr += sizeof(int); + } + + if ((recsDataCompressedSize > 0) && (recsDataCompressedSize != recsDataSize)) + { + // Recs data is compressed, uncompress it + unsigned char *recsDataCompressed = (unsigned char *)RAYGUI_CALLOC(recsDataCompressedSize, sizeof(unsigned char)); + + memcpy(recsDataCompressed, fileDataPtr, recsDataCompressedSize); + fileDataPtr += recsDataCompressedSize; + + int recsDataUncompSize = 0; + font.recs = (Rectangle *)DecompressData(recsDataCompressed, recsDataCompressedSize, &recsDataUncompSize); + + // Security check, data uncompressed size must match the expected original data size + if (recsDataUncompSize != recsDataSize) RAYGUI_LOG("WARNING: Uncompressed font recs data could be corrupted"); + + RAYGUI_FREE(recsDataCompressed); + } + else + { + // Recs data is uncompressed + font.recs = (Rectangle *)RAYGUI_CALLOC(font.glyphCount, sizeof(Rectangle)); + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.recs[i], fileDataPtr, sizeof(Rectangle)); + fileDataPtr += sizeof(Rectangle); + } + } + + // Load font glyphs info data + int glyphsDataSize = font.glyphCount*16; // 16 bytes data per glyph + int glyphsDataCompressedSize = 0; + + // WARNING: Version 400 adds the compression size parameter + if (version >= 400) + { + // RGS files version 400 support compressed glyphs data + memcpy(&glyphsDataCompressedSize, fileDataPtr, sizeof(int)); + fileDataPtr += sizeof(int); + } + + // Allocate required glyphs space to fill with data + font.glyphs = (GlyphInfo *)RAYGUI_CALLOC(font.glyphCount, sizeof(GlyphInfo)); + + if ((glyphsDataCompressedSize > 0) && (glyphsDataCompressedSize != glyphsDataSize)) + { + // Glyphs data is compressed, uncompress it + unsigned char *glypsDataCompressed = (unsigned char *)RAYGUI_CALLOC(glyphsDataCompressedSize, sizeof(unsigned char)); + + memcpy(glypsDataCompressed, fileDataPtr, glyphsDataCompressedSize); + fileDataPtr += glyphsDataCompressedSize; + + int glyphsDataUncompSize = 0; + unsigned char *glyphsDataUncomp = DecompressData(glypsDataCompressed, glyphsDataCompressedSize, &glyphsDataUncompSize); + + // Security check, data uncompressed size must match the expected original data size + if (glyphsDataUncompSize != glyphsDataSize) RAYGUI_LOG("WARNING: Uncompressed font glyphs data could be corrupted"); + + unsigned char *glyphsDataUncompPtr = glyphsDataUncomp; + + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.glyphs[i].value, glyphsDataUncompPtr, sizeof(int)); + memcpy(&font.glyphs[i].offsetX, glyphsDataUncompPtr + 4, sizeof(int)); + memcpy(&font.glyphs[i].offsetY, glyphsDataUncompPtr + 8, sizeof(int)); + memcpy(&font.glyphs[i].advanceX, glyphsDataUncompPtr + 12, sizeof(int)); + glyphsDataUncompPtr += 16; + } + + RAYGUI_FREE(glypsDataCompressed); + RAYGUI_FREE(glyphsDataUncomp); + } + else + { + // Glyphs data is uncompressed + for (int i = 0; i < font.glyphCount; i++) + { + memcpy(&font.glyphs[i].value, fileDataPtr, sizeof(int)); + memcpy(&font.glyphs[i].offsetX, fileDataPtr + 4, sizeof(int)); + memcpy(&font.glyphs[i].offsetY, fileDataPtr + 8, sizeof(int)); + memcpy(&font.glyphs[i].advanceX, fileDataPtr + 12, sizeof(int)); + fileDataPtr += 16; + } + } + +#if defined(RAYGUI_FONT_ICONS_BAKING) + // Font atlas image icons baking + Rectangle updatedWhiteRec = { 0 }; + guiIconFontOffsetY = GuiFontIconBaking(&imFont, font, &updatedWhiteRec); + if (guiIconFontOffsetY > 0) fontWhiteRec = updatedWhiteRec; +#endif + +#if !defined(RAYGUI_STANDALONE) + // Load texture from image + if (font.texture.id != GetFontDefault().texture.id) UnloadTexture(font.texture); + font.texture = LoadTextureFromImage(imFont); + + // Fallback to default raylib texture if font texture loading fails + if (font.texture.id != 0) + { + // Set font texture source rectangle to be used as white texture to draw shapes + // NOTE: It makes possible to draw shapes and text (full UI) in a single draw call + if ((fontWhiteRec.x > 0) && + (fontWhiteRec.y > 0) && + (fontWhiteRec.width > 0) && + (fontWhiteRec.height > 0)) SetShapesTexture(font.texture, fontWhiteRec); + } + else font = GetFontDefault(); + + GuiSetFont(font); +#endif + RAYGUI_FREE(imFont.data); + } + } +} + +// Load style default over global style +void GuiLoadStyleDefault(void) +{ + // Setting this flag first to avoid cyclic function calls + // when calling GuiSetStyle() and GuiGetStyle() + guiStyleLoaded = true; + + // Initialize default LIGHT style property values + // WARNING: Default value are applied to all controls on set but + // they can be overwritten later on for every custom control + GuiSetStyle(DEFAULT, BORDER_COLOR_NORMAL, 0x838383ff); + GuiSetStyle(DEFAULT, BASE_COLOR_NORMAL, 0xc9c9c9ff); + GuiSetStyle(DEFAULT, TEXT_COLOR_NORMAL, 0x686868ff); + GuiSetStyle(DEFAULT, BORDER_COLOR_FOCUSED, 0x5bb2d9ff); + GuiSetStyle(DEFAULT, BASE_COLOR_FOCUSED, 0xc9effeff); + GuiSetStyle(DEFAULT, TEXT_COLOR_FOCUSED, 0x6c9bbcff); + GuiSetStyle(DEFAULT, BORDER_COLOR_PRESSED, 0x0492c7ff); + GuiSetStyle(DEFAULT, BASE_COLOR_PRESSED, 0x97e8ffff); + GuiSetStyle(DEFAULT, TEXT_COLOR_PRESSED, 0x368bafff); + GuiSetStyle(DEFAULT, BORDER_COLOR_DISABLED, 0xb5c1c2ff); + GuiSetStyle(DEFAULT, BASE_COLOR_DISABLED, 0xe6e9e9ff); + GuiSetStyle(DEFAULT, TEXT_COLOR_DISABLED, 0xaeb7b8ff); + GuiSetStyle(DEFAULT, BORDER_WIDTH, 1); + GuiSetStyle(DEFAULT, TEXT_PADDING, 0); + GuiSetStyle(DEFAULT, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + + // Initialize default extended property values + // NOTE: By default, extended property values are initialized to 0 + GuiSetStyle(DEFAULT, TEXT_SIZE, 10); // DEFAULT, shared by all controls + GuiSetStyle(DEFAULT, TEXT_SPACING, 1); // DEFAULT, shared by all controls + GuiSetStyle(DEFAULT, LINE_COLOR, 0x90abb5ff); // DEFAULT specific property + GuiSetStyle(DEFAULT, BACKGROUND_COLOR, 0xf5f5f5ff); // DEFAULT specific property + GuiSetStyle(DEFAULT, TEXT_LINE_SPACING, 12); // DEFAULT, pixels between lines, from bottom of first line to top of second + GuiSetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL, TEXT_ALIGN_MIDDLE); // DEFAULT, text aligned vertically to middle of text-bounds + + // Initialize control-specific property values + // NOTE: Those properties are in default list but require specific values by control type + GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(BUTTON, BORDER_WIDTH, 2); + GuiSetStyle(SLIDER, TEXT_PADDING, 4); + GuiSetStyle(PROGRESSBAR, TEXT_PADDING, 4); + GuiSetStyle(CHECKBOX, TEXT_PADDING, 4); + GuiSetStyle(CHECKBOX, TEXT_ALIGNMENT, TEXT_ALIGN_RIGHT); + GuiSetStyle(DROPDOWNBOX, TEXT_PADDING, 0); + GuiSetStyle(DROPDOWNBOX, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + GuiSetStyle(TEXTBOX, TEXT_PADDING, 4); + GuiSetStyle(TEXTBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(VALUEBOX, TEXT_PADDING, 0); + GuiSetStyle(VALUEBOX, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(STATUSBAR, TEXT_PADDING, 8); + GuiSetStyle(STATUSBAR, TEXT_ALIGNMENT, TEXT_ALIGN_LEFT); + GuiSetStyle(TABBAR, TAB_ITEMS_WIDTH, 160); + + // Initialize extended property values + // NOTE: By default, extended property values are initialized to 0 + GuiSetStyle(TOGGLE, GROUP_PADDING, 2); + GuiSetStyle(SLIDER, SLIDER_WIDTH, 16); + GuiSetStyle(SLIDER, SLIDER_PADDING, 1); + GuiSetStyle(PROGRESSBAR, PROGRESS_PADDING, 1); + GuiSetStyle(CHECKBOX, CHECK_PADDING, 1); + GuiSetStyle(COMBOBOX, COMBO_BUTTON_WIDTH, 32); + GuiSetStyle(COMBOBOX, COMBO_BUTTON_SPACING, 2); + GuiSetStyle(DROPDOWNBOX, ARROW_PADDING, 16); + GuiSetStyle(DROPDOWNBOX, DROPDOWN_ITEMS_SPACING, 2); + GuiSetStyle(VALUEBOX, SPINNER_BUTTON_WIDTH, 24); + GuiSetStyle(VALUEBOX, SPINNER_BUTTON_SPACING, 2); + GuiSetStyle(SCROLLBAR, BORDER_WIDTH, 0); + GuiSetStyle(SCROLLBAR, ARROWS_VISIBLE, 0); + GuiSetStyle(SCROLLBAR, ARROWS_SIZE, 6); + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING, 0); + GuiSetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE, 16); + GuiSetStyle(SCROLLBAR, SCROLL_PADDING, 0); + GuiSetStyle(SCROLLBAR, SCROLL_SPEED, 12); + GuiSetStyle(LISTVIEW, LIST_ITEMS_HEIGHT, 28); + GuiSetStyle(LISTVIEW, LIST_ITEMS_SPACING, 2); + GuiSetStyle(LISTVIEW, LIST_ITEMS_BORDER_WIDTH, 1); + GuiSetStyle(LISTVIEW, SCROLLBAR_WIDTH, 12); + GuiSetStyle(LISTVIEW, SCROLLBAR_SIDE, SCROLLBAR_RIGHT_SIDE); + GuiSetStyle(COLORPICKER, COLOR_SELECTOR_SIZE, 8); + GuiSetStyle(COLORPICKER, HUEBAR_WIDTH, 16); + GuiSetStyle(COLORPICKER, HUEBAR_PADDING, 8); + GuiSetStyle(COLORPICKER, HUEBAR_SELECTOR_HEIGHT, 8); + GuiSetStyle(COLORPICKER, HUEBAR_SELECTOR_OVERFLOW, 2); + + if (guiFont.texture.id != GetFontDefault().texture.id) + { + // Unload previous font texture + UnloadTexture(guiFont.texture); + RAYGUI_FREE(guiFont.recs); + RAYGUI_FREE(guiFont.glyphs); + guiFont.recs = NULL; + guiFont.glyphs = NULL; + + // Setup default raylib font + guiFont = GetFontDefault(); + + // NOTE: Default raylib font character 95 is a white square + Rectangle whiteChar = guiFont.recs[95]; + + // NOTE: Setting up a 1px padding on char rectangle to avoid pixel bleeding on MSAA filtering + SetShapesTexture(guiFont.texture, RAYGUI_CLITERAL(Rectangle){ whiteChar.x + 1, whiteChar.y + 1, whiteChar.width - 2, whiteChar.height - 2 }); + + // Reset baked icons offset in font + guiIconFontOffsetY = 0; + } +} + +// Get text with icon id prepended +// NOTE: Useful to add icons by name id (enum) instead of +// a number that can change between ricon versions +const char *GuiIconText(int iconId, const char *text) +{ +#if defined(RAYGUI_NO_ICONS) + return NULL; +#else + static char buffer[1024] = { 0 }; + static char iconBuffer[16] = { 0 }; + + if (text != NULL) + { + memset(buffer, 0, 1024); + snprintf(buffer, 1024, "#%03i#", iconId); + + for (int i = 5; i < 1024; i++) + { + buffer[i] = text[i - 5]; + if (text[i - 5] == '\0') break; + } + + return buffer; + } + else + { + snprintf(iconBuffer, 16, "#%03i#", iconId); + + return iconBuffer; + } +#endif +} + +#if !defined(RAYGUI_NO_ICONS) +// Get full icons data pointer +unsigned int *GuiGetIcons(void) { return guiIconsPtr; } + +// Load raygui icons file (.rgi) +// WARNING: guiIconsName[]][] memory should be manually freed! +char **GuiLoadIcons(const char *fileName, bool loadIconsName) +{ + FILE *rgiFile = fopen(fileName, "rb"); + char **guiIconsName = NULL; + + if (rgiFile != NULL) + { + unsigned char *fileData = NULL; + int dataSize = 0; + + fseek(rgiFile, 0, SEEK_END); + int size = (int)ftell(rgiFile); + fseek(rgiFile, 0, SEEK_SET); + + if (size > 0) + { + fileData = (unsigned char *)RL_CALLOC(size, sizeof(unsigned char)); + // WARNING: File can be partially loaded but ignoring it for simplicity + dataSize = (int)fread(fileData, sizeof(unsigned char), size, rgiFile); + + guiIconsName = GuiLoadIconsFromMemory(fileData, dataSize, loadIconsName); + } + + fclose(rgiFile); + } + + return guiIconsName; +} + +// Load icons from memory +// GLOBAL: Updates global variable: guiIconsPtr +char **GuiLoadIconsFromMemory(const unsigned char *fileData, int dataSize, bool loadIconsName) +{ + // Icon File Structure (.rgi) + // ------------------------------------------------------ + // Offset | Size | Type | Description + // ------------------------------------------------------ + // 0 | 4 | char | Signature: "rGI " + // 4 | 2 | short | Version: 100, 500 + // 6 | 2 | short | reserved + + // 8 | 2 | short | Num icons (N) + // 10 | 2 | short | Icons Size (Options: 16, 32, 64) + + // Icons name id (32 bytes per name id) + // foreach (icon) + // { + // 12+32*i | 32 | char | Icon NameId + // } + + // Icons data: One bit per pixel, stored as unsigned int array (depends on icon size) + // Size*Size pixels/32bit per unsigned int = K unsigned int per icon + // foreach (icon) + // { + // ... | K | unsigned int | Icon Data + // } + // ------------------------------------------------------ + + unsigned char *fileDataPtr = (unsigned char *)fileData; + char **guiIconsName = NULL; + + char signature[5] = { 0 }; + short version = 0; + short reserved = 0; + short iconCount = 0; + short iconSize = 0; + + memcpy(signature, fileDataPtr, 4); + memcpy(&version, fileDataPtr + 4, sizeof(short)); + memcpy(&reserved, fileDataPtr + 4 + 2, sizeof(short)); + memcpy(&iconCount, fileDataPtr + 4 + 2 + 2, sizeof(short)); + memcpy(&iconSize, fileDataPtr + 4 + 2 + 2 + 2, sizeof(short)); + fileDataPtr += 12; + + if ((signature[0] == 'r') && + (signature[1] == 'G') && + (signature[2] == 'I') && + (signature[3] == ' ')) + { + if (loadIconsName) + { + // NOTE: Always allocating RAYGUI_ICON_MAX_ICONS names slots + guiIconsName = (char **)RAYGUI_CALLOC(RAYGUI_ICON_MAX_ICONS, sizeof(char *)); + for (int i = 0; i < iconCount; i++) + { + guiIconsName[i] = (char *)RAYGUI_CALLOC(RAYGUI_ICON_MAX_NAME_LENGTH, sizeof(char)); + memcpy(guiIconsName[i], fileDataPtr, RAYGUI_ICON_MAX_NAME_LENGTH); + fileDataPtr += RAYGUI_ICON_MAX_NAME_LENGTH; + } + } + else + { + // Skip icon name data if not required + fileDataPtr += iconCount*RAYGUI_ICON_MAX_NAME_LENGTH; + } + + int iconDataSize = iconCount*((int)iconSize*(int)iconSize/32)*(int)sizeof(unsigned int); + guiIconsPtr = (unsigned int *)RAYGUI_CALLOC(iconDataSize, 1); + + memcpy(guiIconsPtr, fileDataPtr, iconDataSize); + } + + return guiIconsName; +} + +// Draw selected icon using rectangles pixel-by-pixel +void GuiDrawIcon(int iconId, int posX, int posY, int pixelSize, Color color) +{ + if ((guiIconFontOffsetY > 0) && (iconId < RAYGUI_ICON_MAX_FONT_BACKED)) + { + int maxIconsPerLine = guiFont.texture.width/(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + int x = iconId%maxIconsPerLine; + int y = iconId/maxIconsPerLine; + + Rectangle srcRec = { (float)x*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + RAYGUI_ICON_FONT_ATLAS_PADDING, + guiIconFontOffsetY + (float)y*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + RAYGUI_ICON_FONT_ATLAS_PADDING, + RAYGUI_ICON_SIZE, RAYGUI_ICON_SIZE }; + Rectangle dstRec = { (float)posX, (float)posY, (float)pixelSize*RAYGUI_ICON_SIZE, (float)pixelSize*RAYGUI_ICON_SIZE }; + + DrawTexturePro(guiFont.texture, srcRec, dstRec, RAYGUI_CLITERAL(Vector2){ 0, 0 }, 0.0f, color); + } + else + { + #define BIT_CHECK(a,b) ((a) & (1u<<(b))) + + for (int i = 0, y = 0; i < RAYGUI_ICON_SIZE*RAYGUI_ICON_SIZE/32; i++) + { + for (int k = 0; k < 32; k++) + { + if (BIT_CHECK(guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i], k)) + { + GuiDrawRectangle(RAYGUI_CLITERAL(Rectangle){ (float)posX + (k%RAYGUI_ICON_SIZE)*pixelSize, + (float)posY + y*pixelSize, (float)pixelSize, (float)pixelSize }, 0, BLANK, color); + } + + if ((k == 15) || (k == 31)) y++; + } + } + } +} + +// Set icon drawing size +void GuiSetIconScale(int scale) +{ + if (scale >= 1) guiIconScale = scale; +} + +// Get text width considering gui style and icon size (if required). +// For multi-line text (containing '\n'), returns the width of the widest line. +int GuiGetTextWidth(const char *text) +{ + if (text == NULL) return 0; + + int maxWidth = 0; + const char *linePtr = text; + + while ((linePtr[0] != '\0') && ((linePtr - text) < MAX_LINE_BUFFER_SIZE)) + { + int lineWidth = GetLineWidth(linePtr); + if (lineWidth > maxWidth) maxWidth = lineWidth; + + // Skip to the next '\n' (or end of string/buffer) + while ((linePtr[0] != '\0') && (linePtr[0] != '\n') && ((linePtr - text) < MAX_LINE_BUFFER_SIZE)) + { + linePtr++; + } + // Advance past the '\n' delimiter to the start of the next line + if (linePtr[0] == '\n') linePtr++; + } + + return maxWidth; +} + +#endif // !RAYGUI_NO_ICONS + +//---------------------------------------------------------------------------------- +// Module Internal Functions Definition +//---------------------------------------------------------------------------------- +// Get text line width (stops at '\n' or '\0') +// NOTE: Considers icon marker '#NNN#' +static int GetLineWidth(const char *text) +{ +#if !defined(RAYGUI_ICON_TEXT_PADDING) + #define RAYGUI_ICON_TEXT_PADDING 4 +#endif + + Vector2 textSize = { 0 }; + int textIconOffset = 0; + + if ((text != NULL) && (text[0] != '\0')) + { + // Icon marker: '#' + 1..3 digits + '#' (matches GetTextIcon()) + if (text[0] == '#') + { + int pos = 1; + while ((pos < 4) && (text[pos] >= '0') && (text[pos] <= '9')) pos++; + if (text[pos] == '#') textIconOffset = pos + 1; + } + + text += textIconOffset; + + // Make sure guiFont is set, GuiGetStyle() initializes it lazynessly + float fontSize = (float)GuiGetStyle(DEFAULT, TEXT_SIZE); + + // Custom MeasureText() implementation -- single line only + if ((guiFont.texture.id > 0) && (text != NULL)) + { + // Get size in bytes of the line, considering end of line and line break + int size = 0; + for (int i = 0; i < MAX_LINE_BUFFER_SIZE; i++) + { + if ((text[i] != '\0') && (text[i] != '\n')) size++; + else break; + } + + float scaleFactor = fontSize/(float)guiFont.baseSize; + textSize.y = (float)guiFont.baseSize*scaleFactor; + float glyphWidth = 0.0f; + + for (int i = 0, codepointSize = 0; i < size; i += codepointSize) + { + int codepoint = GetCodepointNext(&text[i], &codepointSize); + int codepointIndex = GetGlyphIndex(guiFont, codepoint); + + if (guiFont.glyphs[codepointIndex].advanceX == 0) glyphWidth = ((float)guiFont.recs[codepointIndex].width*scaleFactor); + else glyphWidth = ((float)guiFont.glyphs[codepointIndex].advanceX*scaleFactor); + + textSize.x += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + } + } + + if (textIconOffset > 0) textSize.x += (RAYGUI_ICON_SIZE + RAYGUI_ICON_TEXT_PADDING); + } + + return (int)textSize.x; +} + +// Get text bounds considering control bounds +static Rectangle GetTextBounds(int control, Rectangle bounds) +{ + Rectangle textBounds = bounds; + + textBounds.x = bounds.x + GuiGetStyle(control, BORDER_WIDTH); + textBounds.y = bounds.y + GuiGetStyle(control, BORDER_WIDTH) + GuiGetStyle(control, TEXT_PADDING); + textBounds.width = bounds.width - 2*GuiGetStyle(control, BORDER_WIDTH) - 2*GuiGetStyle(control, TEXT_PADDING); + textBounds.height = bounds.height - 2*GuiGetStyle(control, BORDER_WIDTH) - 2*GuiGetStyle(control, TEXT_PADDING); // NOTE: Text is processed line per line! + + // Depending on control, TEXT_PADDING and TEXT_ALIGNMENT properties could affect the text-bounds + switch (control) + { + case COMBOBOX: + case DROPDOWNBOX: + case LISTVIEW: + // TODO: Special cases (no label): COMBOBOX, DROPDOWNBOX, LISTVIEW + case SLIDER: + case CHECKBOX: + case VALUEBOX: + case TABBAR: + // TODO: Special cases (label on side): SLIDER, CHECKBOX, VALUEBOX, SPINNER + default: + { + // WARNING: TEXT_ALIGNMENT is already considered in GuiDrawText() + if (GuiGetStyle(control, TEXT_ALIGNMENT) == TEXT_ALIGN_RIGHT) textBounds.x -= GuiGetStyle(control, TEXT_PADDING); + else textBounds.x += GuiGetStyle(control, TEXT_PADDING); + } + break; + } + + return textBounds; +} + +// Get text icon if provided and move text cursor +// NOTE: Up to RAYGUI_ICON_MAX_ICONS supported for iconId +static const char *GetTextIcon(const char *text, int *iconId) +{ +#if !defined(RAYGUI_NO_ICONS) + *iconId = -1; + if (text[0] == '#') // Maybe an icon, if it starts with # but an ending # must be found + { + char iconValue[4] = { 0 }; // Maximum length for icon value: 3 digits + '\0' + + int pos = 1; + while ((pos < 4) && (text[pos] >= '0') && (text[pos] <= '9')) + { + iconValue[pos - 1] = text[pos]; + pos++; + } + + if (text[pos] == '#') + { + int rawIconId = TextToInteger(iconValue); + if (rawIconId < RAYGUI_ICON_MAX_ICONS) + { + *iconId = rawIconId; + + // Move text pointer after icon + // WARNING: If only icon provided, it could point to EOL character: '\0' + if (*iconId >= 0) text += (pos + 1); + } + } + } +#endif + + return text; +} + +// Get text divided into lines (by line-breaks '\n') +// WARNING: It returns pointers to new lines but it does not add NULL ('\0') terminator! +static const char **GetTextLines(const char *text, int *count) +{ + #define RAYGUI_MAX_TEXT_LINES 128 + + static const char *lines[RAYGUI_MAX_TEXT_LINES] = { 0 }; + for (int i = 0; i < RAYGUI_MAX_TEXT_LINES; i++) lines[i] = NULL; // Init NULL pointers to substrings + + int textLength = (int)strlen(text); + + lines[0] = text; + *count = 1; + + for (int i = 0; (i < textLength) && (*count < RAYGUI_MAX_TEXT_LINES); i++) + { + if ((text[i] == '\n') && ((i + 1) < textLength)) + { + lines[*count] = &text[i + 1]; + *count += 1; + } + } + + return lines; +} + +// Get text width to next space for provided string +static float GetNextSpaceWidth(const char *text, int *nextSpaceIndex) +{ + float width = 0; + int codepointByteCount = 0; + int codepoint = 0; + int index = 0; + float glyphWidth = 0; + float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize; + + for (int i = 0; text[i] != '\0'; i++) + { + if (text[i] != ' ') + { + codepoint = GetCodepoint(&text[i], &codepointByteCount); + index = GetGlyphIndex(guiFont, codepoint); + glyphWidth = (guiFont.glyphs[index].advanceX == 0)? guiFont.recs[index].width*scaleFactor : guiFont.glyphs[index].advanceX*scaleFactor; + width += (glyphWidth + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + } + else + { + *nextSpaceIndex = i; + break; + } + } + + return width; +} + +// Gui draw text using default font +static void GuiDrawText(const char *text, Rectangle textBounds, int alignment, Color tint) +{ + #define TEXT_VALIGN_PIXEL_OFFSET(h) ((int)h%2) // Vertical alignment for pixel perfect + + #if !defined(RAYGUI_ICON_TEXT_PADDING) + #define RAYGUI_ICON_TEXT_PADDING 4 + #endif + + if ((text == NULL) || (text[0] == '\0')) return; // Security check + + // PROCEDURE: + // - Text is processed line per line + // - For every line, horizontal alignment is defined + // - For all text, vertical alignment is defined (multiline text only) + // - For every line, wordwrap mode is checked (useful for GuitextBox(), read-only) + + // Get text lines (using '\n' as delimiter) to be processed individually + // WARNING: GuiTextSplit() function can't be used now because it can have already been used + // before the GuiDrawText() call and its buffer is static, it would be overriden :( + int lineCount = 0; + const char **lines = GetTextLines(text, &lineCount); + + // Text style variables + //int alignment = GuiGetStyle(DEFAULT, TEXT_ALIGNMENT); + int alignmentVertical = GuiGetStyle(DEFAULT, TEXT_ALIGNMENT_VERTICAL); + int wrapMode = GuiGetStyle(DEFAULT, TEXT_WRAP_MODE); // Wrap-mode only available in read-only mode, no for text editing + + // TODO: WARNING: This totalHeight is not valid for vertical alignment in case of word-wrap + float totalHeight = (float)(lineCount*GuiGetStyle(DEFAULT, TEXT_SIZE) + (lineCount - 1)*GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); + float posOffsetY = 0.0f; + + for (int i = 0; i < lineCount; i++) + { + int iconId = 0; + lines[i] = GetTextIcon(lines[i], &iconId); // Check text for icon and move cursor + + // Get text position depending on alignment and iconId + //--------------------------------------------------------------------------------- + Vector2 textBoundsPosition = { textBounds.x, textBounds.y }; + float textBoundsWidthOffset = 0.0f; + + // NOTE: Icon was already stripped above by GetTextIcon(); GetLineWidth() + // takes no icon path here and returns only the glyph width of this line. + int textSizeX = GetLineWidth(lines[i]); + + // If text requires an icon, add size to measure + if (iconId >= 0) + { + textSizeX += RAYGUI_ICON_SIZE*guiIconScale; + + // WARNING: If only icon provided, text could be pointing to EOF character: '\0' +#if !defined(RAYGUI_NO_ICONS) + if ((lines[i] != NULL) && (lines[i][0] != '\0')) textSizeX += RAYGUI_ICON_TEXT_PADDING; +#endif + } + + // Check guiTextAlign global variables + switch (alignment) + { + case TEXT_ALIGN_LEFT: textBoundsPosition.x = textBounds.x; break; + case TEXT_ALIGN_CENTER: textBoundsPosition.x = textBounds.x + textBounds.width/2 - textSizeX/2; break; + case TEXT_ALIGN_RIGHT: textBoundsPosition.x = textBounds.x + textBounds.width - textSizeX; break; + default: break; + } + + if (textSizeX > textBounds.width && (lines[i] != NULL) && (lines[i][0] != '\0')) textBoundsPosition.x = textBounds.x; + + switch (alignmentVertical) + { + // Only valid in case of wordWrap = 0; + case TEXT_ALIGN_TOP: textBoundsPosition.y = textBounds.y + posOffsetY; break; + case TEXT_ALIGN_MIDDLE: textBoundsPosition.y = textBounds.y + posOffsetY + textBounds.height/2 - totalHeight/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height); break; + case TEXT_ALIGN_BOTTOM: textBoundsPosition.y = textBounds.y + posOffsetY + textBounds.height - totalHeight + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height); break; + default: break; + } + + // NOTE: Make sure getting pixel-perfect coordinates, + // In case of decimals, it could result in text positioning artifacts + textBoundsPosition.x = (float)((int)textBoundsPosition.x); + textBoundsPosition.y = (float)((int)textBoundsPosition.y); + //--------------------------------------------------------------------------------- + + // Draw text (with icon if available) + //--------------------------------------------------------------------------------- +#if !defined(RAYGUI_NO_ICONS) + if (iconId >= 0) + { + // NOTE: Considering icon height, probably different than text size + GuiDrawIcon(iconId, (int)textBoundsPosition.x, (int)(textBounds.y + textBounds.height/2 - RAYGUI_ICON_SIZE*guiIconScale/2 + TEXT_VALIGN_PIXEL_OFFSET(textBounds.height)), guiIconScale, tint); + textBoundsPosition.x += (float)(RAYGUI_ICON_SIZE*guiIconScale + RAYGUI_ICON_TEXT_PADDING); + textBoundsWidthOffset = (float)(RAYGUI_ICON_SIZE*guiIconScale + RAYGUI_ICON_TEXT_PADDING); + } +#endif + // Get size in bytes of text, considering end of line and line break + int lineSize = 0; + for (int c = 0; (lines[i][c] != '\0') && (lines[i][c] != '\n') && (lines[i][c] != '\r'); c++, lineSize++){ } + float scaleFactor = (float)GuiGetStyle(DEFAULT, TEXT_SIZE)/guiFont.baseSize; + + int lastSpaceIndex = 0; + bool tempWrapCharMode = false; + + int textOffsetY = 0; + float textOffsetX = 0.0f; + float glyphWidth = 0; + + int ellipsisWidth = GuiGetTextWidth("..."); + bool textOverflow = false; + for (int c = 0, codepointSize = 0; c < lineSize; c += codepointSize) + { + int codepoint = GetCodepointNext(&lines[i][c], &codepointSize); + int index = GetGlyphIndex(guiFont, codepoint); + + // NOTE: Normally, exiting the decoding sequence as soon as a bad byte is found (and return 0x3f) + // but all of the bad bytes need to be drawn using the '?' symbol, moving one byte + if (codepoint == 0x3f) codepointSize = 1; // WARNING: Not recognized codepoints size + + // Get glyph width to check if it goes out of bounds + if (guiFont.glyphs[index].advanceX == 0) glyphWidth = ((float)guiFont.recs[index].width*scaleFactor); + else glyphWidth = (float)guiFont.glyphs[index].advanceX*scaleFactor; + + // Wrap mode text measuring, to validate if + // it can be drawn or a new line is required + if (wrapMode == TEXT_WRAP_CHAR) + { + // Jump to next line if current character reach end of the box limits + if ((textOffsetX + glyphWidth) > textBounds.width - textBoundsWidthOffset) + { + textOffsetX = 0.0f; + textOffsetY += (GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); + + if (tempWrapCharMode) // Wrap at char level when too long words + { + wrapMode = TEXT_WRAP_WORD; + tempWrapCharMode = false; + } + } + } + else if (wrapMode == TEXT_WRAP_WORD) + { + if (codepoint == 32) lastSpaceIndex = c; + + // Get width to next space in line + int nextSpaceIndex = 0; + float nextSpaceWidth = GetNextSpaceWidth(lines[i] + c, &nextSpaceIndex); + + int nextSpaceIndex2 = 0; + float nextWordSize = GetNextSpaceWidth(lines[i] + lastSpaceIndex + 1, &nextSpaceIndex2); + + if (nextWordSize > textBounds.width - textBoundsWidthOffset) + { + // Considering the case the next word is longer than bounds + tempWrapCharMode = true; + wrapMode = TEXT_WRAP_CHAR; + } + else if ((textOffsetX + nextSpaceWidth) > textBounds.width - textBoundsWidthOffset) + { + textOffsetX = 0.0f; + textOffsetY += (GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); + } + } + + if (codepoint == '\n') break; // WARNING: Lines are already processed manually, no need to keep drawing after this codepoint + else + { + // WARNING: There are multiple types of spaces in Unicode, + // maybe it's a good idea to add support for more: http://jkorpela.fi/chars/spaces.html + if ((codepoint != ' ') && (codepoint != '\t')) // Do not draw codepoints with no glyph + { + if (wrapMode == TEXT_WRAP_NONE) + { + // Draw only required text glyphs fitting the textBounds.width + if (textSizeX > textBounds.width) + { + if (textOffsetX <= (textBounds.width - glyphWidth - textBoundsWidthOffset - ellipsisWidth)) + { + DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); + } + else if (!textOverflow) + { + textOverflow = true; + + for (int j = 0; j < ellipsisWidth; j += ellipsisWidth/3) + { + DrawTextCodepoint(guiFont, '.', RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX + j, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); + } + } + } + else + { + DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); + } + } + else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) + { + // Draw only glyphs inside the bounds + if ((textBoundsPosition.y + textOffsetY) <= (textBounds.y + textBounds.height - GuiGetStyle(DEFAULT, TEXT_SIZE))) + { + DrawTextCodepoint(guiFont, codepoint, RAYGUI_CLITERAL(Vector2){ textBoundsPosition.x + textOffsetX, textBoundsPosition.y + textOffsetY }, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), GuiFade(tint, guiAlpha)); + } + } + } + + if (guiFont.glyphs[index].advanceX == 0) textOffsetX += ((float)guiFont.recs[index].width*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + else textOffsetX += ((float)guiFont.glyphs[index].advanceX*scaleFactor + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + } + } + + if (wrapMode == TEXT_WRAP_NONE) posOffsetY += (float)(GuiGetStyle(DEFAULT, TEXT_SIZE) + GuiGetStyle(DEFAULT, TEXT_LINE_SPACING)); + else if ((wrapMode == TEXT_WRAP_CHAR) || (wrapMode == TEXT_WRAP_WORD)) + posOffsetY += (textOffsetY + GuiGetStyle(DEFAULT, TEXT_SIZE)); + //--------------------------------------------------------------------------------- + } + +#if defined(RAYGUI_DEBUG_TEXT_BOUNDS) + GuiDrawRectangle(textBounds, 0, WHITE, Fade(BLUE, 0.4f)); +#endif +} + +// Gui draw rectangle using default raygui plain style with borders +static void GuiDrawRectangle(Rectangle rec, int borderWidth, Color borderColor, Color color) +{ + if (color.a > 0) + { + // Draw rectangle filled with color + DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, GuiFade(color, guiAlpha)); + } + + if (borderWidth > 0) + { + // Draw rectangle border lines with color + DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, borderWidth, GuiFade(borderColor, guiAlpha)); + DrawRectangle((int)rec.x, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, GuiFade(borderColor, guiAlpha)); + DrawRectangle((int)rec.x + (int)rec.width - borderWidth, (int)rec.y + borderWidth, borderWidth, (int)rec.height - 2*borderWidth, GuiFade(borderColor, guiAlpha)); + DrawRectangle((int)rec.x, (int)rec.y + (int)rec.height - borderWidth, (int)rec.width, borderWidth, GuiFade(borderColor, guiAlpha)); + } + +#if defined(RAYGUI_DEBUG_RECS_BOUNDS) + DrawRectangle((int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, Fade(RED, 0.4f)); +#endif +} + +// Draw tooltip using control bounds +static void GuiTooltip(Rectangle controlRec) +{ + if (!guiLocked && guiTooltip && (guiTooltipPtr != NULL) && !guiControlExclusiveMode) + { + Vector2 textSize = MeasureTextEx(guiFont, guiTooltipPtr, (float)GuiGetStyle(DEFAULT, TEXT_SIZE), + (float)GuiGetStyle(DEFAULT, TEXT_SPACING)); + + if ((controlRec.x + textSize.x + 16) > GetScreenWidth()) controlRec.x -= (textSize.x + 16 - controlRec.width); + + int lineCount = 0; + GetTextLines(guiTooltipPtr, &lineCount); // Only using the line count + if ((controlRec.y + controlRec.height + textSize.y + 4 + 8*lineCount) > GetScreenHeight()) + controlRec.y -= (controlRec.height + textSize.y + 4 + 8*lineCount); + + // TODO: Probably TEXT_LINE_SPACING should be considered on panel size instead of hardcoding 8.0f + GuiPanel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, textSize.y + 8.0f*lineCount }, NULL); + + int textPadding = GuiGetStyle(LABEL, TEXT_PADDING); + int textAlignment = GuiGetStyle(LABEL, TEXT_ALIGNMENT); + GuiSetStyle(LABEL, TEXT_PADDING, 0); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, TEXT_ALIGN_CENTER); + GuiLabel(RAYGUI_CLITERAL(Rectangle){ controlRec.x, controlRec.y + controlRec.height + 4, textSize.x + 16, textSize.y + 8.0f*lineCount }, guiTooltipPtr); + GuiSetStyle(LABEL, TEXT_ALIGNMENT, textAlignment); + GuiSetStyle(LABEL, TEXT_PADDING, textPadding); + } +} + +// Scroll bar control (used by GuiScrollPanel()) +static int GuiScrollBar(Rectangle bounds, int value, int minValue, int maxValue) +{ + GuiState state = guiState; + + // Is the scrollbar horizontal or vertical? + bool isVertical = (bounds.width > bounds.height)? false : true; + + // The size (width or height depending on scrollbar type) of the spinner buttons + const int spinnerSize = GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)? + (isVertical? (int)bounds.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) : + (int)bounds.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH)) : 0; + + // Arrow buttons [<] [>] [∧] [∨] + Rectangle arrowUpLeft = { 0 }; + Rectangle arrowDownRight = { 0 }; + + // Actual area of the scrollbar excluding the arrow buttons + Rectangle scrollbar = { 0 }; + + // Slider bar that moves --[///]----- + Rectangle slider = { 0 }; + + // Normalize value + if (value > maxValue) value = maxValue; + if (value < minValue) value = minValue; + + int valueRange = maxValue - minValue; + if (valueRange <= 0) valueRange = 1; + + int sliderSize = GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_SIZE); + if (sliderSize < 1) sliderSize = 1; // Consider a minimum slider size of 1 pixel + + // Calculate rectangles for all of the components + arrowUpLeft = RAYGUI_CLITERAL(Rectangle){ + (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), + (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), + (float)spinnerSize, (float)spinnerSize }; + + if (isVertical) + { + arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + bounds.height - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; + scrollbar = RAYGUI_CLITERAL(Rectangle){ bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), arrowUpLeft.y + arrowUpLeft.height, bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)), bounds.height - arrowUpLeft.height - arrowDownRight.height - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH) }; + + // Make sure the slider won't get outside of the scrollbar + sliderSize = (sliderSize >= scrollbar.height)? ((int)scrollbar.height - 2) : sliderSize; + slider = RAYGUI_CLITERAL(Rectangle){ + bounds.x + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), + scrollbar.y + (int)(((float)(value - minValue)/valueRange)*(scrollbar.height - sliderSize)), + bounds.width - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)), + (float)sliderSize }; + } + else // horizontal + { + arrowDownRight = RAYGUI_CLITERAL(Rectangle){ (float)bounds.x + bounds.width - spinnerSize - GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH), (float)spinnerSize, (float)spinnerSize }; + scrollbar = RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x + arrowUpLeft.width, bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING), bounds.width - arrowUpLeft.width - arrowDownRight.width - 2*GuiGetStyle(SCROLLBAR, BORDER_WIDTH), bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_PADDING)) }; + + // Make sure the slider won't get outside of the scrollbar + sliderSize = (sliderSize >= scrollbar.width)? ((int)scrollbar.width - 2) : sliderSize; + slider = RAYGUI_CLITERAL(Rectangle){ + scrollbar.x + (int)(((float)(value - minValue)/valueRange)*(scrollbar.width - sliderSize)), + bounds.y + GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING), + (float)sliderSize, + bounds.height - 2*(GuiGetStyle(SCROLLBAR, BORDER_WIDTH) + GuiGetStyle(SCROLLBAR, SCROLL_SLIDER_PADDING)) }; + } + + // Update control + //-------------------------------------------------------------------- + if ((state != STATE_DISABLED) && !guiLocked) + { + Vector2 mousePoint = GUI_POINTER_POSITION; + + if (guiControlExclusiveMode) // Allows to keep dragging outside of bounds + { + if (GUI_BUTTON_DOWN && + !CheckCollisionPointRec(mousePoint, arrowUpLeft) && + !CheckCollisionPointRec(mousePoint, arrowDownRight)) + { + if (CHECK_BOUNDS_ID(bounds, guiControlExclusiveRec)) + { + state = STATE_PRESSED; + + if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); + else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); + } + } + else + { + guiControlExclusiveMode = false; + guiControlExclusiveRec = RAYGUI_CLITERAL(Rectangle){ 0, 0, 0, 0 }; + } + } + else if (CheckCollisionPointRec(mousePoint, bounds)) + { + state = STATE_FOCUSED; + + // Handle mouse wheel + float scrollDelta = GUI_SCROLL_DELTA; + if (scrollDelta != 0) value += (int)scrollDelta; + + // Handle mouse button down + if (GUI_BUTTON_PRESSED) + { + guiControlExclusiveMode = true; + guiControlExclusiveRec = bounds; // Store bounds as an identifier when dragging starts + + // Check arrows click + if (CheckCollisionPointRec(mousePoint, arrowUpLeft)) value -= valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + else if (CheckCollisionPointRec(mousePoint, arrowDownRight)) value += valueRange/GuiGetStyle(SCROLLBAR, SCROLL_SPEED); + else if (!CheckCollisionPointRec(mousePoint, slider)) + { + // If click on scrollbar position but not on slider, place slider directly on that position + if (isVertical) value = (int)(((float)(mousePoint.y - scrollbar.y - slider.height/2)*valueRange)/(scrollbar.height - slider.height) + minValue); + else value = (int)(((float)(mousePoint.x - scrollbar.x - slider.width/2)*valueRange)/(scrollbar.width - slider.width) + minValue); + } + + state = STATE_PRESSED; + } + + // Keyboard control on mouse hover scrollbar + /* + if (isVertical) + { + if (GUI_KEY_DOWN(KEY_DOWN)) value += 5; + else if (GUI_KEY_DOWN(KEY_UP)) value -= 5; + } + else + { + if (GUI_KEY_DOWN(KEY_RIGHT)) value += 5; + else if (GUI_KEY_DOWN(KEY_LEFT)) value -= 5; + } + */ + } + + // Normalize value + if (value > maxValue) value = maxValue; + if (value < minValue) value = minValue; + } + //-------------------------------------------------------------------- + + // Draw control + //-------------------------------------------------------------------- + GuiDrawRectangle(bounds, GuiGetStyle(SCROLLBAR, BORDER_WIDTH), GetColor(GuiGetStyle(LISTVIEW, BORDER + state*3)), GetColor(GuiGetStyle(DEFAULT, BORDER_COLOR_DISABLED))); // Draw the background + + GuiDrawRectangle(scrollbar, 0, BLANK, GetColor(GuiGetStyle(BUTTON, BASE_COLOR_NORMAL))); // Draw the scrollbar active area background + GuiDrawRectangle(slider, 0, BLANK, GetColor(GuiGetStyle(SLIDER, BORDER + state*3))); // Draw the slider bar + + // Draw arrows (using icon if available) + if (GuiGetStyle(SCROLLBAR, ARROWS_VISIBLE)) + { +#if defined(RAYGUI_NO_ICONS) + GuiDrawText(isVertical? "^" : "<", + RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); + GuiDrawText(isVertical? "v" : ">", + RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(DROPDOWNBOX, TEXT + (state*3)))); +#else + GuiDrawText(isVertical? GuiIconText(ICON_ARROW_UP_FILL, NULL) : GuiIconText(ICON_ARROW_LEFT_FILL, NULL), + RAYGUI_CLITERAL(Rectangle){ arrowUpLeft.x, arrowUpLeft.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_UP_FILL / ICON_ARROW_LEFT_FILL + GuiDrawText(isVertical? GuiIconText(ICON_ARROW_DOWN_FILL, NULL) : GuiIconText(ICON_ARROW_RIGHT_FILL, NULL), + RAYGUI_CLITERAL(Rectangle){ arrowDownRight.x, arrowDownRight.y, isVertical? bounds.width : bounds.height, isVertical? bounds.width : bounds.height }, + TEXT_ALIGN_CENTER, GetColor(GuiGetStyle(SCROLLBAR, TEXT + state*3))); // ICON_ARROW_DOWN_FILL / ICON_ARROW_RIGHT_FILL +#endif + } + //-------------------------------------------------------------------- + + return value; +} + +// Update font image atlas to append raygui icons +static int GuiFontIconBaking(Image *imFont, Font font, Rectangle *whiteRec) +{ + int iconOffsetY = 0; + + // Check max glyph rec y bottom position in the atlas image, + // to start drawing icons below that line + int maxGlyphRecY = 0; + for (int i = 0; i < font.glyphCount; i++) + { + if ((font.recs[i].y + font.recs[i].height) > maxGlyphRecY) + maxGlyphRecY = (int)font.recs[i].y + (int)font.recs[i].height; + } + + int maxIconsPerLine = imFont->width/(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + int reqIconLines = RAYGUI_ICON_MAX_FONT_BACKED/maxIconsPerLine + RAYGUI_ICON_MAX_FONT_BACKED%maxIconsPerLine + 1; // One extra line + int reqHeight = reqIconLines*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + + // Check if image requires scaling and how much + if ((maxGlyphRecY + reqHeight) > imFont->height) + { + int newImHeight = 1; + while (newImHeight < (maxGlyphRecY + reqHeight)) newImHeight <<= 1; // Round to next POT + + char *newImData = (char *)RL_CALLOC(imFont->width*newImHeight*2, sizeof(char)); + memcpy(newImData, imFont->data, imFont->width*imFont->height*2); + RL_FREE(imFont->data); + + // Clear imFont bottom-right corner rec + for (int y = 0; y < 4; y++) + for (int x = 0; x < 4; x++) + ((unsigned short *)newImData)[(imFont->height - y - 1)*imFont->width + imFont->width - x - 1] = 0x0000; + + imFont->data = newImData; + imFont->height = newImHeight; + + // Set new image white corner and new white rec + for (int y = 0; y < 3; y++) + for (int x = 0; x < 3; x++) + ((unsigned short *)newImData)[(imFont->height - y - 1)*imFont->width + imFont->width - x - 1] = 0xffff; + + *whiteRec = RAYGUI_CLITERAL(Rectangle){ (float)imFont->width - 2, (float)imFont->height - 2, 1, 1 }; + } + + // Calculate image offset positions to start drawing + // NOTE: For Y, look for a multiple of icon size + 2*padding, for better alignment + int offsetX = RAYGUI_ICON_FONT_ATLAS_PADDING; + int offsetY = ((maxGlyphRecY + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING - 1))/ + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING))*(RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING) + + RAYGUI_ICON_FONT_ATLAS_PADDING; + + iconOffsetY = offsetY - RAYGUI_ICON_FONT_ATLAS_PADDING; + unsigned short *pixels = (unsigned short *)imFont->data; + + #define BIT_CHECK(a,b) ((a) & (1u<<(b))) + + for (int iconId = 0; iconId < RAYGUI_ICON_MAX_FONT_BACKED; iconId++) + { + // Wrap to next line if next icon won't fit + if ((offsetX + (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING)) > imFont->width) + { + offsetX = RAYGUI_ICON_FONT_ATLAS_PADDING; + offsetY += RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING; + } + + for (int i = 0, y = 0; i < RAYGUI_ICON_DATA_ELEMENTS; i++) + { + unsigned int data = guiIconsPtr[iconId*RAYGUI_ICON_DATA_ELEMENTS + i]; + + for (int k = 0; k < 32; k++) + { + pixels[(offsetY + y)*imFont->width + offsetX + k%16] = (BIT_CHECK(data, k))? 0xffff : 0x00ff; + + if ((k == 15) || (k == 31)) y++; + } + } + + // Update current icon X position + offsetX += (RAYGUI_ICON_SIZE + 2*RAYGUI_ICON_FONT_ATLAS_PADDING); + } + + return iconOffsetY; +} + +// Split controls text into multiple strings +// NOTE: Re-used by GuiToggleSlider(), GuiComboBox(), GuiDropdownBox(), GuiListView(), GuiMessageBox(), GuiInputBox() +static char **GuiTextSplit(const char *text, char delimiter, int *count) +{ + // NOTE: Current implementation returns a copy of the provided string with '\0' (string end delimiter) + // inserted between strings defined by "delimiter" parameter. No memory is dynamically allocated, + // all used memory is static... it has some limitations: + // 1. Maximum number of possible split strings is set by RAYGUI_TEXTSPLIT_MAX_ITEMS + // 2. Maximum size of text to split is RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE + // NOTE: Those definitions could be externally provided if required + + #if !defined(RAYGUI_TEXTSPLIT_MAX_ITEMS) + #define RAYGUI_TEXTSPLIT_MAX_ITEMS 128 + #endif + #if !defined(RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE) + #define RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE 1024 // WARNING: Max expected size for all concat items + #endif + + static char *itemPtrs[RAYGUI_TEXTSPLIT_MAX_ITEMS] = { 0 }; // String pointers array (points to buffer data) + static char buffer[RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE] = { 0 }; // Buffer data (text input copy with '\0' added) + memset(buffer, 0, RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE); + + itemPtrs[0] = buffer; + int itemCounter = 1; + + // Count how many substrings text contains and point to every one of them + for (int i = 0; i < RAYGUI_TEXTSPLIT_MAX_TEXT_SIZE; i++) + { + buffer[i] = text[i]; + if (buffer[i] == '\0') break; + else if ((buffer[i] == delimiter) || (buffer[i] == '\n')) + { + itemPtrs[itemCounter] = buffer + i + 1; + buffer[i] = '\0'; // Set terminator for current item + + itemCounter++; + if (itemCounter >= RAYGUI_TEXTSPLIT_MAX_ITEMS) break; + } + } + + *count = itemCounter; + return itemPtrs; +} + +// Convert color data from RGB to HSV +// NOTE: Color data should be passed normalized +static Vector3 ConvertRGBtoHSV(Vector3 rgb) +{ + Vector3 hsv = { 0 }; + float min = 0.0f; + float max = 0.0f; + float delta = 0.0f; + + min = (rgb.x < rgb.y)? rgb.x : rgb.y; + min = (min < rgb.z)? min : rgb.z; + + max = (rgb.x > rgb.y)? rgb.x : rgb.y; + max = (max > rgb.z)? max : rgb.z; + + hsv.z = max; // Value + delta = max - min; + + if (delta < 0.00001f) + { + hsv.y = 0.0f; + hsv.x = 0.0f; // Undefined, maybe NAN? + return hsv; + } + + if (max > 0.0f) + { + // NOTE: If max is 0, this divide would cause a crash + hsv.y = (delta/max); // Saturation + } + else + { + // NOTE: If max is 0, then r = g = b = 0, s = 0, h is undefined + hsv.y = 0.0f; + hsv.x = 0.0f; // Undefined, maybe NAN? + return hsv; + } + + // NOTE: Comparing float values could not work properly + if (rgb.x >= max) hsv.x = (rgb.y - rgb.z)/delta; // Between yellow & magenta + else + { + if (rgb.y >= max) hsv.x = 2.0f + (rgb.z - rgb.x)/delta; // Between cyan & yellow + else hsv.x = 4.0f + (rgb.x - rgb.y)/delta; // Between magenta & cyan + } + + hsv.x *= 60.0f; // Convert to degrees + + if (hsv.x < 0.0f) hsv.x += 360.0f; + + return hsv; +} + +// Convert color data from HSV to RGB +// NOTE: Color data should be passed normalized +static Vector3 ConvertHSVtoRGB(Vector3 hsv) +{ + Vector3 rgb = { 0 }; + float hh = 0.0f, p = 0.0f, q = 0.0f, t = 0.0f, ff = 0.0f; + long i = 0; + + // NOTE: Comparing float values could not work properly + if (hsv.y <= 0.0f) + { + rgb.x = hsv.z; + rgb.y = hsv.z; + rgb.z = hsv.z; + return rgb; + } + + hh = hsv.x; + if (hh >= 360.0f) hh = 0.0f; + hh /= 60.0f; + + i = (long)hh; + ff = hh - i; + p = hsv.z*(1.0f - hsv.y); + q = hsv.z*(1.0f - (hsv.y*ff)); + t = hsv.z*(1.0f - (hsv.y*(1.0f - ff))); + + switch (i) + { + case 0: + { + rgb.x = hsv.z; + rgb.y = t; + rgb.z = p; + } break; + case 1: + { + rgb.x = q; + rgb.y = hsv.z; + rgb.z = p; + } break; + case 2: + { + rgb.x = p; + rgb.y = hsv.z; + rgb.z = t; + } break; + case 3: + { + rgb.x = p; + rgb.y = q; + rgb.z = hsv.z; + } break; + case 4: + { + rgb.x = t; + rgb.y = p; + rgb.z = hsv.z; + } break; + case 5: + default: + { + rgb.x = hsv.z; + rgb.y = p; + rgb.z = q; + } break; + } + + return rgb; +} + +// Color fade-in or fade-out, alpha goes from 0.0f to 1.0f +// WARNING: It multiplies current alpha by alpha scale factor, +// raylib Fade() multiplies alpha by 255.0f +static Color GuiFade(Color color, float alpha) +{ + if (alpha < 0.0f) alpha = 0.0f; + else if (alpha > 1.0f) alpha = 1.0f; + + Color result = { color.r, color.g, color.b, (unsigned char)(color.a*alpha) }; + + return result; +} + +#if defined(RAYGUI_STANDALONE) +// Returns a Color struct from hexadecimal value +static Color GetColor(int hexValue) +{ + Color color; + + color.r = (unsigned char)(hexValue >> 24) & 0xff; + color.g = (unsigned char)(hexValue >> 16) & 0xff; + color.b = (unsigned char)(hexValue >> 8) & 0xff; + color.a = (unsigned char)hexValue & 0xff; + + return color; +} + +// Get color with alpha applied, alpha goes from 0.0f to 1.0f +static Color Fade(Color color, float alpha) +{ + Color result = color; + + if (alpha < 0.0f) alpha = 0.0f; + else if (alpha > 1.0f) alpha = 1.0f; + + result.a = (unsigned char)(255.0f*alpha); + + return result; +} + +// Returns hexadecimal value for a Color +static int ColorToInt(Color color) +{ + return (((int)color.r << 24) | ((int)color.g << 16) | ((int)color.b << 8) | (int)color.a); +} + +// Check if point is inside rectangle +static bool CheckCollisionPointRec(Vector2 point, Rectangle rec) +{ + bool collision = false; + + if ((point.x >= rec.x) && (point.x <= (rec.x + rec.width)) && + (point.y >= rec.y) && (point.y <= (rec.y + rec.height))) collision = true; + + return collision; +} + +// Formatting of text with variables to 'embed' +static const char *TextFormat(const char *text, ...) +{ + #if !defined(RAYGUI_TEXTFORMAT_MAX_SIZE) + #define RAYGUI_TEXTFORMAT_MAX_SIZE 256 + #endif + + static char buffer[RAYGUI_TEXTFORMAT_MAX_SIZE] = { 0 }; + memset(buffer, 0, RAYGUI_TEXTFORMAT_MAX_SIZE); + + va_list args; + va_start(args, text); + vsnprintf(buffer, RAYGUI_TEXTFORMAT_MAX_SIZE, text, args); + va_end(args); + + return buffer; +} + +// Get integer value from text +// NOTE: This function replaces atoi() [stdlib.h] +static int TextToInteger(const char *text) +{ + int value = 0; + int sign = 1; + + if ((text[0] == '+') || (text[0] == '-')) + { + if (text[0] == '-') sign = -1; + text++; + } + + for (int i = 0; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10 + (int)(text[i] - '0'); + + return value*sign; +} + +// Get float value from text +// NOTE: This function replaces atof() [stdlib.h] +// WARNING: Only '.' character is understood as decimal point +static float TextToFloat(const char *text) +{ + float value = 0.0f; + float sign = 1.0f; + + if ((text[0] == '+') || (text[0] == '-')) + { + if (text[0] == '-') sign = -1.0f; + text++; + } + + int i = 0; + for (; ((text[i] >= '0') && (text[i] <= '9')); i++) value = value*10.0f + (float)(text[i] - '0'); + + if (text[i++] != '.') value *= sign; + else + { + float divisor = 10.0f; + for (; ((text[i] >= '0') && (text[i] <= '9')); i++) + { + value += ((float)(text[i] - '0'))/divisor; + divisor = divisor*10.0f; + } + } + + return value; +} + +// Encode codepoint into UTF-8 text (char array size returned as parameter) +static const char *CodepointToUTF8(int codepoint, int *byteSize) +{ + static char utf8[6] = { 0 }; + int size = 0; + + if (codepoint <= 0x7f) + { + utf8[0] = (char)codepoint; + size = 1; + } + else if (codepoint <= 0x7ff) + { + utf8[0] = (char)(((codepoint >> 6) & 0x1f) | 0xc0); + utf8[1] = (char)((codepoint & 0x3f) | 0x80); + size = 2; + } + else if (codepoint <= 0xffff) + { + utf8[0] = (char)(((codepoint >> 12) & 0x0f) | 0xe0); + utf8[1] = (char)(((codepoint >> 6) & 0x3f) | 0x80); + utf8[2] = (char)((codepoint & 0x3f) | 0x80); + size = 3; + } + else if (codepoint <= 0x10ffff) + { + utf8[0] = (char)(((codepoint >> 18) & 0x07) | 0xf0); + utf8[1] = (char)(((codepoint >> 12) & 0x3f) | 0x80); + utf8[2] = (char)(((codepoint >> 6) & 0x3f) | 0x80); + utf8[3] = (char)((codepoint & 0x3f) | 0x80); + size = 4; + } + + *byteSize = size; + + return utf8; +} + +// Get next codepoint in a UTF-8 encoded text, scanning until '\0' is found +// When a invalid UTF-8 byte is encountered, exiting as soon as possible and returning a '?'(0x3f) codepoint +// Total number of bytes processed are returned as a parameter +// NOTE: The standard says U+FFFD should be returned in case of errors +// but that character is not supported by the default font in raylib +static int GetCodepointNext(const char *text, int *codepointSize) +{ + const char *ptr = text; + int codepoint = 0x3f; // Codepoint (defaults to '?') + *codepointSize = 1; + + // Get current codepoint and bytes processed + if (0xf0 == (0xf8 & ptr[0])) + { + // 4 byte UTF-8 codepoint + if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80) || ((ptr[3] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks + codepoint = ((0x07 & ptr[0]) << 18) | ((0x3f & ptr[1]) << 12) | ((0x3f & ptr[2]) << 6) | (0x3f & ptr[3]); + *codepointSize = 4; + } + else if (0xe0 == (0xf0 & ptr[0])) + { + // 3 byte UTF-8 codepoint + if (((ptr[1] & 0xC0) ^ 0x80) || ((ptr[2] & 0xC0) ^ 0x80)) { return codepoint; } //10xxxxxx checks + codepoint = ((0x0f & ptr[0]) << 12) | ((0x3f & ptr[1]) << 6) | (0x3f & ptr[2]); + *codepointSize = 3; + } + else if (0xc0 == (0xe0 & ptr[0])) + { + // 2 byte UTF-8 codepoint + if ((ptr[1] & 0xC0) ^ 0x80) { return codepoint; } //10xxxxxx checks + codepoint = ((0x1f & ptr[0]) << 6) | (0x3f & ptr[1]); + *codepointSize = 2; + } + else if (0x00 == (0x80 & ptr[0])) + { + // 1 byte UTF-8 codepoint + codepoint = ptr[0]; + *codepointSize = 1; + } + + return codepoint; +} +#endif // RAYGUI_STANDALONE + +#endif // RAYGUI_IMPLEMENTATION From 9fd4726c313f9d680b629d8504e56db6bcd721e6 Mon Sep 17 00:00:00 2001 From: Matthew Roush Date: Tue, 21 Jul 2026 11:46:22 -0400 Subject: [PATCH 84/94] [rshapes] Fix `DrawRectangleRoundedLines()` (#5992) In #5980 a bug was introduced for `DrawRectangleRoundedLines()`. `DrawRectangleRoundedLines()` previously assumed that `DrawRectangleRoundedLinesEx()` uses `RL_LINES` when line thickness is 1 (which is no longer true, it now uses `RL_QUADS` or `RL_TRIANGLES`.) I copy/pasted the previous `DrawRectangleRoundedLinesEx()` implementation and trimmed it down (since now the line thickness is always 1), so now `DrawRectangleRoundedLines()` uses `RL_LINES`. This makes it consistent with all other `Draw*Lines()` functions, which use `RL_LINES`. --- src/rshapes.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/src/rshapes.c b/src/rshapes.c index def6d36b2..7292212b1 100644 --- a/src/rshapes.c +++ b/src/rshapes.c @@ -888,7 +888,90 @@ void DrawRectangleRounded(Rectangle rec, float roundness, int segments, Color co // Draw rectangle with rounded edges void DrawRectangleRoundedLines(Rectangle rec, float roundness, int segments, Color color) { - DrawRectangleRoundedLinesEx(rec, roundness, segments, 1.0f, color); + // Not a rounded rectangle + if (roundness <= 0.0f) + { + DrawRectangleLines((int)rec.x, (int)rec.y, (int)rec.width, (int)rec.height, color); + return; + } + + if (roundness >= 1.0f) roundness = 1.0f; + + // Calculate corner radius + float radius = (rec.width > rec.height)? (rec.height*roundness)/2 : (rec.width*roundness)/2; + if (radius <= 0.0f) return; + + // Calculate number of segments to use for the corners + if (segments < 4) + { + // Calculate the maximum angle between segments based on the error rate (usually 0.5f) + float th = acosf(2*powf(1 - SMOOTH_CIRCLE_ERROR_RATE/radius, 2) - 1); + segments = (int)ceilf((2*PI/th)/4.0f); + if (segments <= 0) segments = 4; + } + + float stepLength = 90.0f/(float)segments; + + /* + Quick sketch to make sense of all of this, + marks the 8 + 4 (corner centers P8-11) points used + + P0 ------------------ P1 + / \ + / \ + P7 / \ P2 + | *P8 P9* | + | | + | | + P6 \ *P11 P10* / P3 + \ / + \ / + P5 ------------------ P4 + */ + const Vector2 point[8] = { + {(float)rec.x + radius + 0.5f, rec.y + 0.5f}, + {(float)(rec.x + rec.width) - radius - 0.5f, rec.y + 0.5f}, + {rec.x + rec.width - 0.5f, (float)rec.y + radius + 0.5f}, // PO, P1, P2 + {rec.x + rec.width - 0.5f, (float)(rec.y + rec.height) - radius - 0.5f}, + {(float)(rec.x + rec.width) - radius - 0.5f, rec.y + rec.height - 0.5f}, // P3, P4 + {(float)rec.x + radius + 0.5f, rec.y + rec.height - 0.5f}, + {rec.x + 0.5f, (float)(rec.y + rec.height) - radius - 0.5f}, + {rec.x + 0.5f, (float)rec.y + radius + 0.5f}, // P5, P6, P7 + }; + + const Vector2 centers[4] = { + {(float)rec.x + radius + 0.5f, (float)rec.y + radius + 0.5f}, + {(float)(rec.x + rec.width) - radius - 0.5f, (float)rec.y + radius + 0.5f}, // P16, P17 + {(float)(rec.x + rec.width) - radius - 0.5f, (float)(rec.y + rec.height) - radius - 0.5f}, + {(float)rec.x + radius + 0.5f, (float)(rec.y + rec.height) - radius - 0.5f} // P18, P19 + }; + + const float angles[4] = { 180.0f, 270.0f, 0.0f, 90.0f }; + + rlBegin(RL_LINES); + // Draw all the 4 corners first: Upper Left Corner, Upper Right Corner, Lower Right Corner, Lower Left Corner + for (int k = 0; k < 4; ++k) // Hope the compiler is smart enough to unroll this loop + { + float angle = angles[k]; + const Vector2 center = centers[k]; + + for (int i = 0; i < segments; i++) + { + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(center.x + cosf(DEG2RAD*angle)*radius, center.y + sinf(DEG2RAD*angle)*radius); + rlVertex2f(center.x + cosf(DEG2RAD*(angle + stepLength))*radius, center.y + sinf(DEG2RAD*(angle + stepLength))*radius); + angle += stepLength; + } + } + + // And now the remaining 4 lines + for (int i = 0; i < 8; i += 2) + { + rlColor4ub(color.r, color.g, color.b, color.a); + rlVertex2f(point[i].x, point[i].y); + rlVertex2f(point[i + 1].x, point[i + 1].y); + } + rlEnd(); } // Draw rectangle with rounded edges outline with line thickness From e809face7b26f8fc43eac9a790e5867af2596e0d Mon Sep 17 00:00:00 2001 From: oscujic <52619003+oscujic@users.noreply.github.com> Date: Tue, 21 Jul 2026 09:48:07 -0600 Subject: [PATCH 85/94] [rmodels] `DrawSphereWires()`, code optimization (#6000) * Fix DrawSphereWires (Less aggressively) Summary: - Eliminated some redundancies - Fixed a bug(?) where the sphere would have 1 more "ring" (latitude division) than expected - Fixed a bug where the top ring was double-covered - Added comments denoting which code draws which lines * DrawSphereWires + DrawSphereEx parity Summary: - Replaced DrawSphereWires algorithm with one based on the much faster algorithm from DrawSphereEx - Fixed +1 ring quirk on DrawSphereEx to match the change made to DrawSphereWires --- src/rmodels.c | 53 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index 0325f9b1b..119ac315a 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -488,7 +488,7 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color rlBegin(RL_TRIANGLES); rlColor4ub(color.r, color.g, color.b, color.a); - float ringangle = DEG2RAD*(180.0f/(rings + 1)); // Angle between latitudinal parallels + float ringangle = DEG2RAD*(180.0f/rings); // Angle between latitudinal parallels float sliceangle = DEG2RAD*(360.0f/slices); // Angle between longitudinal meridians float cosring = cosf(ringangle); @@ -500,7 +500,7 @@ void DrawSphereEx(Vector3 centerPos, float radius, int rings, int slices, Color vertices[2] = (Vector3){ 0, 1, 0 }; vertices[3] = (Vector3){ sinring, cosring, 0 }; - for (int i = 0; i < rings + 1; i++) + for (int i = 0; i < rings; i++) { for (int j = 0; j < slices; j++) { @@ -542,31 +542,42 @@ void DrawSphereWires(Vector3 centerPos, float radius, int rings, int slices, Col rlBegin(RL_LINES); rlColor4ub(color.r, color.g, color.b, color.a); - for (int i = 0; i < (rings + 2); i++) + float ringangle = DEG2RAD*(180.0f/rings); // Angle between latitudinal parallels + float sliceangle = DEG2RAD*(360.0f/slices); // Angle between longitudinal meridians + + float cosring = cosf(ringangle); + float sinring = sinf(ringangle); + float cosslice = cosf(sliceangle); + float sinslice = sinf(sliceangle); + + Vector3 vertices[4] = { 0 }; // Required to store face vertices + vertices[2] = (Vector3){ 0, 1, 0 }; + vertices[3] = (Vector3){ sinring, cosring, 0 }; + + for (int i = 0; i < rings; i++) { for (int j = 0; j < slices; j++) { - rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)), - sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)), - cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices))); - rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)), - sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))), - cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices))); + vertices[0] = vertices[2]; // Rotate around y axis to set up vertices for next face + vertices[1] = vertices[3]; + vertices[2] = (Vector3){ cosslice*vertices[2].x - sinslice*vertices[2].z, vertices[2].y, sinslice*vertices[2].x + cosslice*vertices[2].z }; // Rotation matrix around y axis + vertices[3] = (Vector3){ cosslice*vertices[3].x - sinslice*vertices[3].z, vertices[3].y, sinslice*vertices[3].x + cosslice*vertices[3].z }; - rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*(j + 1)/slices)), - sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))), - cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*(j + 1)/slices))); - rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*j/slices)), - sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))), - cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*j/slices))); + // Longitude Lines + rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z); + rlVertex3f(vertices[1].x, vertices[1].y, vertices[1].z); - rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*sinf(DEG2RAD*(360.0f*j/slices)), - sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1))), - cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*(i + 1)))*cosf(DEG2RAD*(360.0f*j/slices))); - rlVertex3f(cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*sinf(DEG2RAD*(360.0f*j/slices)), - sinf(DEG2RAD*(270 + (180.0f/(rings + 1))*i)), - cosf(DEG2RAD*(270 + (180.0f/(rings + 1))*i))*cosf(DEG2RAD*(360.0f*j/slices))); + // Latitude Lines + rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z); + rlVertex3f(vertices[2].x, vertices[2].y, vertices[2].z); + + // Diagonal Lines + rlVertex3f(vertices[0].x, vertices[0].y, vertices[0].z); + rlVertex3f(vertices[3].x, vertices[3].y, vertices[3].z); } + + vertices[2] = vertices[3]; // Rotate around z axis to set up starting vertices for next ring + vertices[3] = (Vector3){ cosring*vertices[3].x + sinring*vertices[3].y, -sinring*vertices[3].x + cosring*vertices[3].y, vertices[3].z }; // Rotation matrix around z axis } rlEnd(); rlPopMatrix(); From 78535d2343d07ad456a123ffb5b5c617320712c6 Mon Sep 17 00:00:00 2001 From: Colin James Wood <82226641+NighthowlerStudios@users.noreply.github.com> Date: Tue, 21 Jul 2026 17:20:58 +0100 Subject: [PATCH 86/94] [rlsw] First batch of embedded optimizations and compiler requirements Pico 2 (#5994) * pico doesn't implement time.h * add option for RLSW to hold a back buffer, and give it a sw method to swap * Remove unused pointer and give swSwapColorBuffers a default nop-behaviour * Fix compilation by removing old colorBackBuffer setters * use the correct logger * return line * rename RLSW_BACKBUFFER to SW_DOUBLE_BUFFERING --- src/external/rlsw.h | 34 ++++++++++++++++++++++++++++++++++ src/rcore.c | 11 ++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/external/rlsw.h b/src/external/rlsw.h index db10bf2b4..00f1d97ec 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -677,6 +677,7 @@ SWAPI bool swResize(int w, int h); SWAPI void swReadPixels(int x, int y, int w, int h, SWformat format, SWtype type, void *pixels); SWAPI void swBlitPixels(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, SWformat format, SWtype type, void *pixels); SWAPI void *swGetColorBuffer(int *width, int *height); // Restored for ESP-IDF compatibility +SWAPI void swSwapColorBuffers(void); // Swap software renderer color/back buffers by pointer only SWAPI void swEnable(SWstate state); SWAPI void swDisable(SWstate state); @@ -993,6 +994,9 @@ typedef struct { typedef struct { sw_texture_t color; // Default framebuffer color texture +#ifdef SW_DOUBLE_BUFFERING + sw_texture_t backColor; // Back buffer for multicore. +#endif sw_texture_t depth; // Default framebuffer depth texture } sw_default_framebuffer_t; @@ -1061,6 +1065,7 @@ typedef struct { sw_handle_t boundFramebufferId; // Framebuffer currently bound sw_texture_t *colorBuffer; // Color buffer currently bound + // NOTE: don't need backBuffer because it's already in the sw_default_framebuffer_t struct. sw_texture_t *depthBuffer; // Depth buffer currently bound sw_pool_t framebufferPool; // Framebuffer object pool @@ -2583,6 +2588,13 @@ static inline bool sw_default_framebuffer_alloc(sw_default_framebuffer_t *fb, in return false; } +#ifdef SW_DOUBLE_BUFFERING + if (!sw_texture_alloc(&fb->backColor, NULL, w, h, SW_FRAMEBUFFER_COLOR_FORMAT)) + { + return false; + } +#endif + if (!sw_texture_alloc(&fb->depth, NULL, w, h, SW_FRAMEBUFFER_DEPTH_FORMAT)) { return false; @@ -2595,6 +2607,9 @@ static inline void sw_default_framebuffer_free(sw_default_framebuffer_t *fb) { sw_texture_free(&fb->color); sw_texture_free(&fb->depth); +#ifdef SW_DOUBLE_BUFFERING + sw_texture_free(&fb->backColor); +#endif } static inline void sw_framebuffer_fill_color(sw_texture_t *colorBuffer, const float color[4]) @@ -4160,6 +4175,22 @@ void *swGetColorBuffer(int *width, int *height) return RLSW.framebuffer.color.pixels; } + +void swSwapColorBuffers(void) +{ +#ifdef SW_DOUBLE_BUFFERING + sw_texture_t tmp = RLSW.framebuffer.color; + RLSW.framebuffer.color = RLSW.framebuffer.backColor; + RLSW.framebuffer.backColor = tmp; + + // Only needs to know about current colorBuffer. + RLSW.colorBuffer = &RLSW.framebuffer.color; +#else + SW_LOG("WARNING: RLSW: swSwapColorBuffers not enabled (#define SW_DOUBLE_BUFFERING with a compiler option to enable).\n"); +#endif +} + + void swEnable(SWstate state) { switch (state) @@ -4335,6 +4366,8 @@ void swClear(uint32_t bitmask) sw_framebuffer_fill_color(RLSW.colorBuffer, RLSW.clearColor); } + // Don't clear back buffer, it might be locked by another core. + if ((bitmask & (SW_DEPTH_BUFFER_BIT)) && (RLSW.depthBuffer != NULL) && (RLSW.depthBuffer->pixels != NULL)) { sw_framebuffer_fill_depth(RLSW.depthBuffer, RLSW.clearDepth); @@ -5266,6 +5299,7 @@ void swBindFramebuffer(uint32_t id) RLSW.boundFramebufferId = id; RLSW.colorBuffer = sw_pool_get(&RLSW.texturePool, fb->colorAttachment); + // No back buffer available for binding rendertextures. RLSW.depthBuffer = sw_pool_get(&RLSW.texturePool, fb->depthAttachment); } diff --git a/src/rcore.c b/src/rcore.c index 450a4cec5..27b80b3c9 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -110,7 +110,12 @@ #include // Required for: FILE, fopen(), fseek(), ftell(), fread(), fwrite(), fprintf(), vprintf(), fclose(), sprintf() [Used in OpenURL()] #include // Required for: strlen(), strcmp(), strrchr(), memset(), memcpy(), strcat() #include // Required for: va_list, va_start(), va_end() [Used in TraceLog()] + +#ifndef PICO_RP2350 #include // Required for: time() [Used in InitTimer()] +#else +#include "pico/rand.h" // Pico doesn't implement time, and will implement its own hardware timer elsewhere. However, we need something to get a random seed from... +#endif #include // Required for: tan() [Used in BeginMode3D()], atan2f() [Used in LoadVrStereoConfig()] #if defined(PLATFORM_MEMORY) || defined(PLATFORM_WEB) @@ -713,8 +718,12 @@ void InitWindow(int width, int height, const char *title) CORE.Time.frameCounter = 0; CORE.Window.shouldClose = false; - // Initialize random seed + // Initialize random seed using available timer source instead of standard time() on embedded platforms + #ifndef PICO_RP2350 SetRandomSeed((unsigned int)time(NULL)); + #else + SetRandomSeed(get_rand_32()); + #endif TRACELOG(LOG_INFO, "SYSTEM: Working Directory: %s", GetWorkingDirectory()); } From aa4cf20eaeeda0165e890c9a10c3fd772a75380f Mon Sep 17 00:00:00 2001 From: Bigfoot <90587919+Bigfoot71@users.noreply.github.com> Date: Tue, 21 Jul 2026 18:22:58 +0200 Subject: [PATCH 87/94] [rlsw] Variant dispatch refactor + bunch of improvements (#5996) * rlsw config section * use raster flags to define rasterizer variants * simplifies the generation of dispatch tables * single dispatch table for the lines same logic as for the points * internal color interp state * check whether vertex colors should be interpolated * vector op helper macro + pick sampler once before primitive drawing * op order tweaks * refactoring without gotos for triangle and quad rasterizers * same cleaning for the lines --- src/external/rlsw.h | 1482 ++++++++++++++++++++----------------------- 1 file changed, 683 insertions(+), 799 deletions(-) diff --git a/src/external/rlsw.h b/src/external/rlsw.h index 00f1d97ec..1434fd868 100644 --- a/src/external/rlsw.h +++ b/src/external/rlsw.h @@ -93,34 +93,8 @@ #include //---------------------------------------------------------------------------------- -// Defines and Macros +// RLSW Configuration //---------------------------------------------------------------------------------- -// Function specifiers definition -#ifndef SWAPI - #define SWAPI // Functions defined as 'extern' by default (implicit specifiers) -#endif - -#ifndef SW_MALLOC - #define SW_MALLOC(sz) malloc(sz) -#endif -#ifndef SW_CALLOC - #define SW_CALLOC(n,sz) calloc(n,sz) -#endif -#ifndef SW_REALLOC - #define SW_REALLOC(ptr, newSz) realloc(ptr, newSz) -#endif -#ifndef SW_FREE - #define SW_FREE(ptr) free(ptr) -#endif - -#ifndef SW_RESTRICT - #ifdef _MSC_VER - #define SW_RESTRICT __restrict - #else - #define SW_RESTRICT restrict - #endif -#endif - #ifndef SW_FRAMEBUFFER_OUTPUT_BGRA #define SW_FRAMEBUFFER_OUTPUT_BGRA true #endif @@ -167,7 +141,38 @@ // Full NPOT texture support (enabled by default) // When disabled, SW_REPEAT requires POT on its axis (fast bitmask wrap) // SW_CLAMP remains supported for any dimension, per-axis -#define SW_SUPPORT_NPOT_TEXTURE true +#ifndef SW_SUPPORT_NPOT_TEXTURE +# define SW_SUPPORT_NPOT_TEXTURE true +#endif + +//---------------------------------------------------------------------------------- +// Defines and Macros +//---------------------------------------------------------------------------------- +// Function specifiers definition +#ifndef SWAPI + #define SWAPI // Functions defined as 'extern' by default (implicit specifiers) +#endif + +#ifndef SW_MALLOC + #define SW_MALLOC(sz) malloc(sz) +#endif +#ifndef SW_CALLOC + #define SW_CALLOC(n,sz) calloc(n,sz) +#endif +#ifndef SW_REALLOC + #define SW_REALLOC(ptr, newSz) realloc(ptr, newSz) +#endif +#ifndef SW_FREE + #define SW_FREE(ptr) free(ptr) +#endif + +#ifndef SW_RESTRICT + #ifdef _MSC_VER + #define SW_RESTRICT __restrict + #else + #define SW_RESTRICT restrict + #endif +#endif //---------------------------------------------------------------------------------- // OpenGL Compatibility Types @@ -787,6 +792,18 @@ SWAPI void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWatta #define SW_ALIGN(x) // Do nothing if not available #endif +#if defined(NDEBUG) + #if defined(_MSC_VER) + #define SW_INLINE __forceinline + #elif defined(__GNUC__) || defined(__clang__) + #define SW_INLINE inline __attribute__((always_inline)) + #else + #define SW_INLINE inline + #endif +#else + #define SW_INLINE inline +#endif + #if defined(_M_X64) || defined(__x86_64__) #define SW_ARCH_X86_64 #elif defined(_M_IX86) || defined(__i386__) @@ -902,11 +919,13 @@ SWAPI void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWatta #define SW_FRAMEBUFFER_COLOR_SIZE SW_PIXELFORMAT_SIZE[SW_FRAMEBUFFER_COLOR_FORMAT] #define SW_FRAMEBUFFER_DEPTH_SIZE SW_PIXELFORMAT_SIZE[SW_FRAMEBUFFER_DEPTH_FORMAT] +#define SW_STATE_NONE 0 /* Pseudo state used for the rasterizer variant with no pipeline state enabled */ #define SW_STATE_SCISSOR_TEST (1 << 0) -#define SW_STATE_TEXTURE_2D (1 << 1) -#define SW_STATE_DEPTH_TEST (1 << 2) -#define SW_STATE_CULL_FACE (1 << 3) -#define SW_STATE_BLEND (1 << 4) +#define SW_STATE_COLOR_INTERP (1 << 1) +#define SW_STATE_TEXTURE_2D (1 << 2) +#define SW_STATE_DEPTH_TEST (1 << 3) +#define SW_STATE_CULL_FACE (1 << 4) +#define SW_STATE_BLEND (1 << 5) #define SW_BLEND_FLAG_NOOP (1 << 0) #define SW_BLEND_FLAG_NEEDS_ALPHA (1 << 1) @@ -948,6 +967,7 @@ typedef enum { } sw_pixel_alpha_t; // Forward declarations +typedef struct sw_texture sw_texture_t; typedef struct sw_vertex sw_vertex_t; // Pixel getter functions @@ -958,6 +978,9 @@ typedef void (*sw_pixel_read_color_f)(float *SW_RESTRICT, const void *SW_RESTRIC typedef void (*sw_pixel_write_color8_f)(void *SW_RESTRICT, const uint8_t *SW_RESTRICT, uint32_t); typedef void (*sw_pixel_write_color_f)(void *SW_RESTRICT, const float *SW_RESTRICT, uint32_t); +// Texture sampler function +typedef void (*sw_texture_sampler_f)(float *SW_RESTRICT, const sw_texture_t *SW_RESTRICT, float, float); + // Color blending function typedef void (*sw_blend_f)(float *SW_RESTRICT, const float *SW_RESTRICT); @@ -975,7 +998,7 @@ typedef struct sw_vertex { float texcoord[2]; // Texture coordinates } sw_vertex_t; -typedef struct { +typedef struct sw_texture { void *pixels; // Texture pixels sw_pixel_read_color8_f readColor8; // Texel read RGBA8 sw_pixel_read_color_f readColor; // Texel read RGBA32F @@ -1153,6 +1176,13 @@ static const int SW_PRIMITIVE_VERTEX_COUNT[] = // Internal Functions Definitions //---------------------------------------------------------------------------------- +// Common helper macros +//---------------------------------------------------------------------------------- +#define SW_VEC_OP(expr, i_name, count) do { \ + for (int i_name = 0; i_name < (count); i_name++) expr; \ +} while (0) +//---------------------------------------------------------------------------------- + // Math helper functions //---------------------------------------------------------------------------------- static inline void sw_matrix_id(sw_matrix_t dst) @@ -1243,16 +1273,15 @@ static inline float sw_fract(float x) return (x - floorf(x)); } -// Xtensa architecture optimization -// Fast reciprocal: 1-ULP accurate in ~7 instructions using the -// hardware `recip0.s` seed + two Newton-Raphson refinement steps -// All work stays in FPU registers — no `__divsf3` software call -// Hot-path divisions in the rasterizer (span/triangle setup, perspective divide, etc.) call this -// On non-Xtensa targets it transparently expands to `1.0f / x`, so generated code is identical to before -#if defined(__XTENSA__) -__attribute__((always_inline)) -static inline float sw_rcp(float x) +static SW_INLINE float sw_rcp(float x) { +#if defined(__XTENSA__) + // Xtensa architecture optimization + // Fast reciprocal: 1-ULP accurate in ~7 instructions using the + // hardware `recip0.s` seed + two Newton-Raphson refinement steps + // All work stays in FPU registers — no `__divsf3` software call + // Hot-path divisions in the rasterizer (span/triangle setup, perspective divide, etc.) call this + // On non-Xtensa targets it transparently expands to `1.0f / x`, so generated code is identical to before float result, temp; __asm__( "recip0.s %0, %2\n" @@ -1265,10 +1294,10 @@ static inline float sw_rcp(float x) : "=&f"(result), "=&f"(temp) : "f"(x) ); return result; -} #else -static inline float sw_rcp(float x) { return 1.0f/x; } + return 1.0f/x; #endif +} static inline uint8_t sw_luminance8(const uint8_t *color) { @@ -1301,108 +1330,6 @@ static inline void sw_lerp_vertex_PCT(sw_vertex_t *SW_RESTRICT out, const sw_ver out->texcoord[1] = a->texcoord[1]*tInv + b->texcoord[1]*t; } -static inline void sw_get_vertex_grad_PCT(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float scale) -{ - // Calculate gradients for Position - out->position[0] = (b->position[0] - a->position[0])*scale; - out->position[1] = (b->position[1] - a->position[1])*scale; - out->position[2] = (b->position[2] - a->position[2])*scale; - out->position[3] = (b->position[3] - a->position[3])*scale; - - // Calculate gradients for Color - out->color[0] = (b->color[0] - a->color[0])*scale; - out->color[1] = (b->color[1] - a->color[1])*scale; - out->color[2] = (b->color[2] - a->color[2])*scale; - out->color[3] = (b->color[3] - a->color[3])*scale; - - // Calculate gradients for Texture coordinates - out->texcoord[0] = (b->texcoord[0] - a->texcoord[0])*scale; - out->texcoord[1] = (b->texcoord[1] - a->texcoord[1])*scale; -} - -static inline void sw_add_vertex_grad_PCT(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients) -{ - // Add gradients to Position - out->position[0] += gradients->position[0]; - out->position[1] += gradients->position[1]; - out->position[2] += gradients->position[2]; - out->position[3] += gradients->position[3]; - - // Add gradients to Color - out->color[0] += gradients->color[0]; - out->color[1] += gradients->color[1]; - out->color[2] += gradients->color[2]; - out->color[3] += gradients->color[3]; - - // Add gradients to Texture coordinates - out->texcoord[0] += gradients->texcoord[0]; - out->texcoord[1] += gradients->texcoord[1]; -} - -static inline void sw_add_vertex_grad_scaled_PCT(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients, float scale) -{ - // Add gradients to Position - out->position[0] += gradients->position[0]*scale; - out->position[1] += gradients->position[1]*scale; - out->position[2] += gradients->position[2]*scale; - out->position[3] += gradients->position[3]*scale; - - // Add gradients to Color - out->color[0] += gradients->color[0]*scale; - out->color[1] += gradients->color[1]*scale; - out->color[2] += gradients->color[2]*scale; - out->color[3] += gradients->color[3]*scale; - - // Add gradients to Texture coordinates - out->texcoord[0] += gradients->texcoord[0]*scale; - out->texcoord[1] += gradients->texcoord[1]*scale; -} - -static inline void sw_get_vertex_grad_PC(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float scale) -{ - // Calculate gradients for Position - out->position[0] = (b->position[0] - a->position[0])*scale; - out->position[1] = (b->position[1] - a->position[1])*scale; - out->position[2] = (b->position[2] - a->position[2])*scale; - out->position[3] = (b->position[3] - a->position[3])*scale; - - // Calculate gradients for Color - out->color[0] = (b->color[0] - a->color[0])*scale; - out->color[1] = (b->color[1] - a->color[1])*scale; - out->color[2] = (b->color[2] - a->color[2])*scale; - out->color[3] = (b->color[3] - a->color[3])*scale; -} - -static inline void sw_add_vertex_grad_PC(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients) -{ - // Add gradients to Position - out->position[0] += gradients->position[0]; - out->position[1] += gradients->position[1]; - out->position[2] += gradients->position[2]; - out->position[3] += gradients->position[3]; - - // Add gradients to Color - out->color[0] += gradients->color[0]; - out->color[1] += gradients->color[1]; - out->color[2] += gradients->color[2]; - out->color[3] += gradients->color[3]; -} - -static inline void sw_add_vertex_grad_scaled_PC(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients, float scale) -{ - // Add gradients to Position - out->position[0] += gradients->position[0]*scale; - out->position[1] += gradients->position[1]*scale; - out->position[2] += gradients->position[2]*scale; - out->position[3] += gradients->position[3]*scale; - - // Add gradients to Color - out->color[0] += gradients->color[0]*scale; - out->color[1] += gradients->color[1]*scale; - out->color[2] += gradients->color[2]*scale; - out->color[3] += gradients->color[3]*scale; -} - // Half conversion functions static inline uint16_t sw_float_to_half_ui(uint32_t ui) { @@ -2553,8 +2480,8 @@ static inline void sw_texture_sample_linear(float *SW_RESTRICT color, const sw_t } } -static inline void sw_texture_sample(float *SW_RESTRICT color, const sw_texture_t *SW_RESTRICT tex, - float u, float v, float dUdx, float dUdy, float dVdx, float dVdy) +// Resolves which sample function to use from the texel-to-pixel derivative magnitude +static inline sw_texture_sampler_f sw_texture_pick_sampler(const sw_texture_t *tex, const float dTdx[2], const float dTdy[2]) { // NOTE: Commented there is the previous method used // There was no need to compute the square root because @@ -2563,19 +2490,12 @@ static inline void sw_texture_sample(float *SW_RESTRICT color, const sw_texture_ //float dv = sqrtf(dVdx*dVdx + dVdy*dVdy); //float L = (du > dv)? du : dv; - // Calculate the derivatives for each axis - float dU2 = dUdx*dUdx + dUdy*dUdy; - float dV2 = dVdx*dVdx + dVdy*dVdy; + float dU2 = dTdx[0]*dTdx[0] + dTdy[0]*dTdy[0]; + float dV2 = dTdx[1]*dTdx[1] + dTdy[1]*dTdy[1]; float L2 = (dU2 > dV2)? dU2 : dV2; SWfilter filter = (L2 > 1.0f)? tex->minFilter : tex->magFilter; - - switch (filter) - { - case SW_NEAREST: sw_texture_sample_nearest(color, tex, u, v); break; - case SW_LINEAR: sw_texture_sample_linear(color, tex, u, v); break; - default: break; - } + return (filter == SW_LINEAR)? sw_texture_sample_linear : sw_texture_sample_nearest; } //------------------------------------------------------------------------------------------- @@ -3071,330 +2991,298 @@ static bool sw_polygon_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES] return (n >= 3); } +// Rasterizer variant generation macros +//------------------------------------------------------------------------------------------- +// Argument count (1-4) +#define SW_NARGS_(_1,_2,_3,_4,N,...) N +#define SW_NARGS(...) SW_NARGS_(__VA_ARGS__,4,3,2,1) + +// State tokens -> OR'd SW_STATE_xxx flags +#define SW_OR1(a) (SW_STATE_##a) +#define SW_OR2(a,b) (SW_STATE_##a | SW_STATE_##b) +#define SW_OR3(a,b,c) (SW_STATE_##a | SW_STATE_##b | SW_STATE_##c) +#define SW_OR4(a,b,c,d) (SW_STATE_##a | SW_STATE_##b | SW_STATE_##c | SW_STATE_##d) +#define SW_FLAGS_(N, ...) SW_CONCATX(SW_OR, N)(__VA_ARGS__) +#define SW_FLAGS(...) SW_FLAGS_(SW_NARGS(__VA_ARGS__), __VA_ARGS__) + +// State tokens -> function name suffix +#define SW_CAT1(a) a +#define SW_CAT2(a,b) a##_##b +#define SW_CAT3(a,b,c) a##_##b##_##c +#define SW_CAT4(a,b,c,d) a##_##b##_##c##_##d +#define SW_NAME_(N, ...) SW_CONCATX(SW_CAT, N)(__VA_ARGS__) +#define SW_NAME(...) SW_NAME_(SW_NARGS(__VA_ARGS__), __VA_ARGS__) + +// Forward decl for one variant; SIG is a parenthesized param list +#define SW_RASTER_FWD(PREFIX, SIG, ...) \ + static void SW_CONCATX(PREFIX, SW_NAME(__VA_ARGS__)) SIG; + +// Dispatch table entry for one variant +#define SW_RASTER_ENTRY(PREFIX, ...) \ + [SW_FLAGS(__VA_ARGS__)] = SW_CONCATX(PREFIX, SW_NAME(__VA_ARGS__)), + +// Variant lists: X(STATES...) invoked once per specialization +// Triangle/quad: COLOR_INTERP, TEXTURE_2D, DEPTH_TEST, BLEND +#define SW_RASTER_VARIANTS_4(X, ...) \ + X(__VA_ARGS__, NONE) \ + X(__VA_ARGS__, COLOR_INTERP) \ + X(__VA_ARGS__, TEXTURE_2D) \ + X(__VA_ARGS__, DEPTH_TEST) \ + X(__VA_ARGS__, BLEND) \ + X(__VA_ARGS__, COLOR_INTERP, TEXTURE_2D) \ + X(__VA_ARGS__, COLOR_INTERP, DEPTH_TEST) \ + X(__VA_ARGS__, COLOR_INTERP, BLEND) \ + X(__VA_ARGS__, TEXTURE_2D, DEPTH_TEST) \ + X(__VA_ARGS__, TEXTURE_2D, BLEND) \ + X(__VA_ARGS__, DEPTH_TEST, BLEND) \ + X(__VA_ARGS__, COLOR_INTERP, TEXTURE_2D, DEPTH_TEST) \ + X(__VA_ARGS__, COLOR_INTERP, TEXTURE_2D, BLEND) \ + X(__VA_ARGS__, COLOR_INTERP, DEPTH_TEST, BLEND) \ + X(__VA_ARGS__, TEXTURE_2D, DEPTH_TEST, BLEND) \ + X(__VA_ARGS__, COLOR_INTERP, TEXTURE_2D, DEPTH_TEST, BLEND) + +// Variant lists: X(STATES...) invoked once per specialization +// Line: COLOR_INTERP, DEPTH_TEST, BLEND +#define SW_RASTER_VARIANTS_3(X, ...) \ + X(__VA_ARGS__, NONE) \ + X(__VA_ARGS__, COLOR_INTERP) \ + X(__VA_ARGS__, DEPTH_TEST) \ + X(__VA_ARGS__, BLEND) \ + X(__VA_ARGS__, COLOR_INTERP, DEPTH_TEST) \ + X(__VA_ARGS__, COLOR_INTERP, BLEND) \ + X(__VA_ARGS__, DEPTH_TEST, BLEND) \ + X(__VA_ARGS__, COLOR_INTERP, DEPTH_TEST, BLEND) + +// Point: DEPTH_TEST, BLEND +#define SW_RASTER_VARIANTS_2(X, ...) \ + X(__VA_ARGS__, NONE) \ + X(__VA_ARGS__, DEPTH_TEST) \ + X(__VA_ARGS__, BLEND) \ + X(__VA_ARGS__, DEPTH_TEST, BLEND) +//------------------------------------------------------------------------------------------- + // Triangle rasterizer variant dispatch //------------------------------------------------------------------------------------------- -#ifndef RLSW_TEMPLATE_RASTER_TRIANGLE_EXPANDING -#define RLSW_TEMPLATE_RASTER_TRIANGLE_EXPANDING +#define SW_RASTER_TRIANGLE_STATE_MASK SW_FLAGS(COLOR_INTERP, TEXTURE_2D, DEPTH_TEST, BLEND) - // State mask to apply before indexing the dispatch table - #define SW_RASTER_TRIANGLE_STATE_MASK \ - (SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND) +#define SW_RASTER_TRIANGLE_STATES NONE +#include __FILE__ // IWYU pragma: keep +#undef SW_RASTER_TRIANGLE_STATES - // Single source of truth for all rasterizer specializations - // X(NAME, STATE_FLAGS) - #define SW_RASTER_VARIANTS(X) \ - X(BASE, 0) \ - X(TEX, SW_STATE_TEXTURE_2D) \ - X(DEPTH, SW_STATE_DEPTH_TEST) \ - X(BLEND, SW_STATE_BLEND) \ - X(TEX_DEPTH, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST) \ - X(TEX_BLEND, SW_STATE_TEXTURE_2D | SW_STATE_BLEND) \ - X(DEPTH_BLEND, SW_STATE_DEPTH_TEST | SW_STATE_BLEND) \ - X(TEX_DEPTH_BLEND, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND) +#define SW_RASTER_TRIANGLE_STATES COLOR_INTERP +#include __FILE__ +#undef SW_RASTER_TRIANGLE_STATES - // Forward declarations because clangd does not follow #include __FILE__ to avoid infinite recursion - // These declarations make all variants visible to static analysis tools without affecting compilation - #define SW_FWD_DECL(NAME, _FLAGS) \ - static void sw_raster_triangle_##NAME(const sw_vertex_t*, const sw_vertex_t*, const sw_vertex_t*); - SW_RASTER_VARIANTS(SW_FWD_DECL) // NOLINT - #undef SW_FWD_DECL +#define SW_RASTER_TRIANGLE_STATES TEXTURE_2D +#include __FILE__ +#undef SW_RASTER_TRIANGLE_STATES - // Specialization generation via self-inclusion +#define SW_RASTER_TRIANGLE_STATES DEPTH_TEST +#include __FILE__ +#undef SW_RASTER_TRIANGLE_STATES - #define RLSW_TEMPLATE_RASTER_TRIANGLE BASE - #include __FILE__ // IWYU pragma: keep - #undef RLSW_TEMPLATE_RASTER_TRIANGLE +#define SW_RASTER_TRIANGLE_STATES BLEND +#include __FILE__ +#undef SW_RASTER_TRIANGLE_STATES - #define RLSW_TEMPLATE_RASTER_TRIANGLE TEX - #define SW_ENABLE_TEXTURE - #include __FILE__ - #undef SW_ENABLE_TEXTURE - #undef RLSW_TEMPLATE_RASTER_TRIANGLE +#define SW_RASTER_TRIANGLE_STATES COLOR_INTERP, TEXTURE_2D +#include __FILE__ +#undef SW_RASTER_TRIANGLE_STATES - #define RLSW_TEMPLATE_RASTER_TRIANGLE DEPTH - #define SW_ENABLE_DEPTH_TEST - #include __FILE__ - #undef SW_ENABLE_DEPTH_TEST - #undef RLSW_TEMPLATE_RASTER_TRIANGLE +#define SW_RASTER_TRIANGLE_STATES COLOR_INTERP, DEPTH_TEST +#include __FILE__ +#undef SW_RASTER_TRIANGLE_STATES - #define RLSW_TEMPLATE_RASTER_TRIANGLE BLEND - #define SW_ENABLE_BLEND - #include __FILE__ - #undef SW_ENABLE_BLEND - #undef RLSW_TEMPLATE_RASTER_TRIANGLE +#define SW_RASTER_TRIANGLE_STATES COLOR_INTERP, BLEND +#include __FILE__ +#undef SW_RASTER_TRIANGLE_STATES - #define RLSW_TEMPLATE_RASTER_TRIANGLE TEX_DEPTH - #define SW_ENABLE_TEXTURE - #define SW_ENABLE_DEPTH_TEST - #include __FILE__ - #undef SW_ENABLE_DEPTH_TEST - #undef SW_ENABLE_TEXTURE - #undef RLSW_TEMPLATE_RASTER_TRIANGLE +#define SW_RASTER_TRIANGLE_STATES TEXTURE_2D, DEPTH_TEST +#include __FILE__ +#undef SW_RASTER_TRIANGLE_STATES - #define RLSW_TEMPLATE_RASTER_TRIANGLE TEX_BLEND - #define SW_ENABLE_TEXTURE - #define SW_ENABLE_BLEND - #include __FILE__ - #undef SW_ENABLE_BLEND - #undef SW_ENABLE_TEXTURE - #undef RLSW_TEMPLATE_RASTER_TRIANGLE +#define SW_RASTER_TRIANGLE_STATES TEXTURE_2D, BLEND +#include __FILE__ +#undef SW_RASTER_TRIANGLE_STATES - #define RLSW_TEMPLATE_RASTER_TRIANGLE DEPTH_BLEND - #define SW_ENABLE_DEPTH_TEST - #define SW_ENABLE_BLEND - #include __FILE__ - #undef SW_ENABLE_BLEND - #undef SW_ENABLE_DEPTH_TEST - #undef RLSW_TEMPLATE_RASTER_TRIANGLE +#define SW_RASTER_TRIANGLE_STATES DEPTH_TEST, BLEND +#include __FILE__ +#undef SW_RASTER_TRIANGLE_STATES - #define RLSW_TEMPLATE_RASTER_TRIANGLE TEX_DEPTH_BLEND - #define SW_ENABLE_TEXTURE - #define SW_ENABLE_DEPTH_TEST - #define SW_ENABLE_BLEND - #include __FILE__ - #undef SW_ENABLE_BLEND - #undef SW_ENABLE_DEPTH_TEST - #undef SW_ENABLE_TEXTURE - #undef RLSW_TEMPLATE_RASTER_TRIANGLE +#define SW_RASTER_TRIANGLE_STATES COLOR_INTERP, TEXTURE_2D, DEPTH_TEST +#include __FILE__ +#undef SW_RASTER_TRIANGLE_STATES - // Dispatch table (auto-generated from SW_RASTER_VARIANTS) - #define SW_TABLE_ENTRY(NAME, FLAGS) [FLAGS] = sw_raster_triangle_##NAME, - static const sw_raster_triangle_f SW_RASTER_TRIANGLE_TABLE[] = { - SW_RASTER_VARIANTS(SW_TABLE_ENTRY) - }; - #undef SW_TABLE_ENTRY +#define SW_RASTER_TRIANGLE_STATES COLOR_INTERP, DEPTH_TEST, BLEND +#include __FILE__ +#undef SW_RASTER_TRIANGLE_STATES -#undef SW_RASTER_VARIANTS -#undef RLSW_TEMPLATE_RASTER_TRIANGLE_EXPANDING +#define SW_RASTER_TRIANGLE_STATES COLOR_INTERP, TEXTURE_2D, BLEND +#include __FILE__ +#undef SW_RASTER_TRIANGLE_STATES -#endif // RLSW_TEMPLATE_RASTER_TRIANGLE_EXPANDING +#define SW_RASTER_TRIANGLE_STATES TEXTURE_2D, DEPTH_TEST, BLEND +#include __FILE__ +#undef SW_RASTER_TRIANGLE_STATES + +#define SW_RASTER_TRIANGLE_STATES COLOR_INTERP, TEXTURE_2D, DEPTH_TEST, BLEND +#include __FILE__ +#undef SW_RASTER_TRIANGLE_STATES + +// Forward declarations for static analyzer like clangd that do not handle self-inclusion correctly +SW_RASTER_VARIANTS_4(SW_RASTER_FWD, sw_raster_triangle_, (const sw_vertex_t*, const sw_vertex_t*, const sw_vertex_t*)) // NOLINT + +static const sw_raster_triangle_f SW_RASTER_TRIANGLE_TABLE[] = { + SW_RASTER_VARIANTS_4(SW_RASTER_ENTRY, sw_raster_triangle_) +}; //------------------------------------------------------------------------------------------- // Quad rasterizer variant dispatch //------------------------------------------------------------------------------------------- -#ifndef RLSW_TEMPLATE_RASTER_QUAD_EXPANDING -#define RLSW_TEMPLATE_RASTER_QUAD_EXPANDING +#define SW_RASTER_QUAD_STATE_MASK SW_FLAGS(COLOR_INTERP, TEXTURE_2D, DEPTH_TEST, BLEND) - // State mask to apply before indexing the dispatch table - #define SW_RASTER_QUAD_STATE_MASK \ - (SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND) +#define SW_RASTER_QUAD_STATES NONE +#include __FILE__ // IWYU pragma: keep +#undef SW_RASTER_QUAD_STATES - // Single source of truth for all rasterizer specializations - // X(NAME, STATE_FLAGS) - #define SW_RASTER_VARIANTS(X) \ - X(BASE, 0) \ - X(TEX, SW_STATE_TEXTURE_2D) \ - X(DEPTH, SW_STATE_DEPTH_TEST) \ - X(BLEND, SW_STATE_BLEND) \ - X(TEX_DEPTH, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST) \ - X(TEX_BLEND, SW_STATE_TEXTURE_2D | SW_STATE_BLEND) \ - X(DEPTH_BLEND, SW_STATE_DEPTH_TEST | SW_STATE_BLEND) \ - X(TEX_DEPTH_BLEND, SW_STATE_TEXTURE_2D | SW_STATE_DEPTH_TEST | SW_STATE_BLEND) +#define SW_RASTER_QUAD_STATES COLOR_INTERP +#include __FILE__ +#undef SW_RASTER_QUAD_STATES - // Forward declarations because clangd does not follow #include __FILE__ to avoid infinite recursion - // These declarations make all variants visible to static analysis tools without affecting compilation - #define SW_FWD_DECL(NAME, _FLAGS) \ - static void sw_raster_quad_##NAME(const sw_vertex_t *v0, const sw_vertex_t *v1, const sw_vertex_t *v2, const sw_vertex_t *v3); - SW_RASTER_VARIANTS(SW_FWD_DECL) // NOLINT - #undef SW_FWD_DECL +#define SW_RASTER_QUAD_STATES TEXTURE_2D +#include __FILE__ +#undef SW_RASTER_QUAD_STATES - // Specialization generation via self-inclusion +#define SW_RASTER_QUAD_STATES DEPTH_TEST +#include __FILE__ +#undef SW_RASTER_QUAD_STATES - #define RLSW_TEMPLATE_RASTER_QUAD BASE - #include __FILE__ // IWYU pragma: keep - #undef RLSW_TEMPLATE_RASTER_QUAD +#define SW_RASTER_QUAD_STATES BLEND +#include __FILE__ +#undef SW_RASTER_QUAD_STATES - #define RLSW_TEMPLATE_RASTER_QUAD TEX - #define SW_ENABLE_TEXTURE - #include __FILE__ - #undef SW_ENABLE_TEXTURE - #undef RLSW_TEMPLATE_RASTER_QUAD +#define SW_RASTER_QUAD_STATES COLOR_INTERP, TEXTURE_2D +#include __FILE__ +#undef SW_RASTER_QUAD_STATES - #define RLSW_TEMPLATE_RASTER_QUAD DEPTH - #define SW_ENABLE_DEPTH_TEST - #include __FILE__ - #undef SW_ENABLE_DEPTH_TEST - #undef RLSW_TEMPLATE_RASTER_QUAD +#define SW_RASTER_QUAD_STATES COLOR_INTERP, DEPTH_TEST +#include __FILE__ +#undef SW_RASTER_QUAD_STATES - #define RLSW_TEMPLATE_RASTER_QUAD BLEND - #define SW_ENABLE_BLEND - #include __FILE__ - #undef SW_ENABLE_BLEND - #undef RLSW_TEMPLATE_RASTER_QUAD +#define SW_RASTER_QUAD_STATES COLOR_INTERP, BLEND +#include __FILE__ +#undef SW_RASTER_QUAD_STATES - #define RLSW_TEMPLATE_RASTER_QUAD TEX_DEPTH - #define SW_ENABLE_TEXTURE - #define SW_ENABLE_DEPTH_TEST - #include __FILE__ - #undef SW_ENABLE_DEPTH_TEST - #undef SW_ENABLE_TEXTURE - #undef RLSW_TEMPLATE_RASTER_QUAD +#define SW_RASTER_QUAD_STATES TEXTURE_2D, DEPTH_TEST +#include __FILE__ +#undef SW_RASTER_QUAD_STATES - #define RLSW_TEMPLATE_RASTER_QUAD TEX_BLEND - #define SW_ENABLE_TEXTURE - #define SW_ENABLE_BLEND - #include __FILE__ - #undef SW_ENABLE_BLEND - #undef SW_ENABLE_TEXTURE - #undef RLSW_TEMPLATE_RASTER_QUAD +#define SW_RASTER_QUAD_STATES TEXTURE_2D, BLEND +#include __FILE__ +#undef SW_RASTER_QUAD_STATES - #define RLSW_TEMPLATE_RASTER_QUAD DEPTH_BLEND - #define SW_ENABLE_DEPTH_TEST - #define SW_ENABLE_BLEND - #include __FILE__ - #undef SW_ENABLE_BLEND - #undef SW_ENABLE_DEPTH_TEST - #undef RLSW_TEMPLATE_RASTER_QUAD +#define SW_RASTER_QUAD_STATES DEPTH_TEST, BLEND +#include __FILE__ +#undef SW_RASTER_QUAD_STATES - #define RLSW_TEMPLATE_RASTER_QUAD TEX_DEPTH_BLEND - #define SW_ENABLE_TEXTURE - #define SW_ENABLE_DEPTH_TEST - #define SW_ENABLE_BLEND - #include __FILE__ - #undef SW_ENABLE_BLEND - #undef SW_ENABLE_DEPTH_TEST - #undef SW_ENABLE_TEXTURE - #undef RLSW_TEMPLATE_RASTER_QUAD +#define SW_RASTER_QUAD_STATES COLOR_INTERP, TEXTURE_2D, DEPTH_TEST +#include __FILE__ +#undef SW_RASTER_QUAD_STATES - // Dispatch table (auto-generated from SW_RASTER_VARIANTS) - #define SW_TABLE_ENTRY(NAME, FLAGS) [FLAGS] = sw_raster_quad_##NAME, - static const sw_raster_quad_f SW_RASTER_QUAD_TABLE[] = { - SW_RASTER_VARIANTS(SW_TABLE_ENTRY) - }; - #undef SW_TABLE_ENTRY +#define SW_RASTER_QUAD_STATES COLOR_INTERP, TEXTURE_2D, BLEND +#include __FILE__ +#undef SW_RASTER_QUAD_STATES -#undef SW_RASTER_VARIANTS -#undef RLSW_TEMPLATE_RASTER_QUAD_EXPANDING +#define SW_RASTER_QUAD_STATES COLOR_INTERP, DEPTH_TEST, BLEND +#include __FILE__ +#undef SW_RASTER_QUAD_STATES -#endif // RLSW_TEMPLATE_RASTER_QUAD_EXPANDING +#define SW_RASTER_QUAD_STATES TEXTURE_2D, DEPTH_TEST, BLEND +#include __FILE__ +#undef SW_RASTER_QUAD_STATES + +#define SW_RASTER_QUAD_STATES COLOR_INTERP, TEXTURE_2D, DEPTH_TEST, BLEND +#include __FILE__ +#undef SW_RASTER_QUAD_STATES + +// Forward declarations for static analyzer like clangd that do not handle self-inclusion correctly +SW_RASTER_VARIANTS_4(SW_RASTER_FWD, sw_raster_quad_, (const sw_vertex_t*, const sw_vertex_t*, const sw_vertex_t*, const sw_vertex_t*)) // NOLINT + +static const sw_raster_quad_f SW_RASTER_QUAD_TABLE[] = { + SW_RASTER_VARIANTS_4(SW_RASTER_ENTRY, sw_raster_quad_) +}; //------------------------------------------------------------------------------------------- // Line rasterizer variant dispatch //------------------------------------------------------------------------------------------- -#ifndef RLSW_TEMPLATE_RASTER_LINE_EXPANDING -#define RLSW_TEMPLATE_RASTER_LINE_EXPANDING +#define SW_RASTER_LINE_STATE_MASK SW_FLAGS(COLOR_INTERP, DEPTH_TEST, BLEND) - // State mask to apply before indexing the dispatch table - #define SW_RASTER_LINE_STATE_MASK \ - (SW_STATE_DEPTH_TEST | SW_STATE_BLEND) +#define SW_RASTER_LINE_STATES NONE +#include __FILE__ // IWYU pragma: keep +#undef SW_RASTER_LINE_STATES - // Single source of truth for all rasterizer specializations - // X(NAME, STATE_FLAGS) - #define SW_RASTER_VARIANTS(X) \ - X(BASE, 0) \ - X(DEPTH, SW_STATE_DEPTH_TEST) \ - X(BLEND, SW_STATE_BLEND) \ - X(DEPTH_BLEND, SW_STATE_DEPTH_TEST | SW_STATE_BLEND) +#define SW_RASTER_LINE_STATES COLOR_INTERP +#include __FILE__ +#undef SW_RASTER_LINE_STATES - // Forward declarations because clangd does not follow #include __FILE__ to avoid infinite recursion - // These declarations make all variants visible to static analysis tools without affecting compilation - #define SW_FWD_DECL(NAME, _FLAGS) \ - static void sw_raster_line_##NAME(const sw_vertex_t *v0, const sw_vertex_t *v1); \ - static void sw_raster_line_thick_##NAME(const sw_vertex_t *v0, const sw_vertex_t *v1); - SW_RASTER_VARIANTS(SW_FWD_DECL) // NOLINT - #undef SW_FWD_DECL +#define SW_RASTER_LINE_STATES DEPTH_TEST +#include __FILE__ +#undef SW_RASTER_LINE_STATES - // Specialization generation via self-inclusion +#define SW_RASTER_LINE_STATES BLEND +#include __FILE__ +#undef SW_RASTER_LINE_STATES - #define RLSW_TEMPLATE_RASTER_LINE BASE - #include __FILE__ // IWYU pragma: keep - #undef RLSW_TEMPLATE_RASTER_LINE +#define SW_RASTER_LINE_STATES COLOR_INTERP, DEPTH_TEST +#include __FILE__ +#undef SW_RASTER_LINE_STATES - #define RLSW_TEMPLATE_RASTER_LINE DEPTH - #define SW_ENABLE_DEPTH_TEST - #include __FILE__ - #undef SW_ENABLE_DEPTH_TEST - #undef RLSW_TEMPLATE_RASTER_LINE +#define SW_RASTER_LINE_STATES COLOR_INTERP, BLEND +#include __FILE__ +#undef SW_RASTER_LINE_STATES - #define RLSW_TEMPLATE_RASTER_LINE BLEND - #define SW_ENABLE_BLEND - #include __FILE__ - #undef SW_ENABLE_BLEND - #undef RLSW_TEMPLATE_RASTER_LINE +#define SW_RASTER_LINE_STATES DEPTH_TEST, BLEND +#include __FILE__ +#undef SW_RASTER_LINE_STATES - #define RLSW_TEMPLATE_RASTER_LINE DEPTH_BLEND - #define SW_ENABLE_DEPTH_TEST - #define SW_ENABLE_BLEND - #include __FILE__ - #undef SW_ENABLE_BLEND - #undef SW_ENABLE_DEPTH_TEST - #undef RLSW_TEMPLATE_RASTER_LINE +#define SW_RASTER_LINE_STATES COLOR_INTERP, DEPTH_TEST, BLEND +#include __FILE__ +#undef SW_RASTER_LINE_STATES - // Dispatch table (auto-generated from SW_RASTER_VARIANTS) - #define SW_TABLE_ENTRY0(NAME, FLAGS) [FLAGS] = sw_raster_line_##NAME, - #define SW_TABLE_ENTRY1(NAME, FLAGS) [FLAGS] = sw_raster_line_thick_##NAME, - static const sw_raster_line_f SW_RASTER_LINE_TABLE[] = { SW_RASTER_VARIANTS(SW_TABLE_ENTRY0) }; - static const sw_raster_line_f SW_RASTER_LINE_THICK_TABLE[] = { SW_RASTER_VARIANTS(SW_TABLE_ENTRY1) }; - #undef SW_TABLE_ENTRY0 - #undef SW_TABLE_ENTRY1 +// Forward declarations for static analyzer like clangd that do not handle self-inclusion correctly +SW_RASTER_VARIANTS_3(SW_RASTER_FWD, sw_raster_line_, (const sw_vertex_t*, const sw_vertex_t*)) // NOLINT -#undef SW_RASTER_VARIANTS -#undef RLSW_TEMPLATE_RASTER_LINE_EXPANDING - -#endif // RLSW_TEMPLATE_RASTER_LINE_EXPANDING +static const sw_raster_line_f SW_RASTER_LINE_TABLE[] = { + SW_RASTER_VARIANTS_3(SW_RASTER_ENTRY, sw_raster_line_) +}; //------------------------------------------------------------------------------------------- // Point rasterizer variant dispatch //------------------------------------------------------------------------------------------- -#ifndef RLSW_TEMPLATE_RASTER_POINT_EXPANDING -#define RLSW_TEMPLATE_RASTER_POINT_EXPANDING +#define SW_RASTER_POINT_STATE_MASK SW_FLAGS(DEPTH_TEST, BLEND) - // State mask to apply before indexing the dispatch table - #define SW_RASTER_POINT_STATE_MASK \ - (SW_STATE_DEPTH_TEST | SW_STATE_BLEND) +#define SW_RASTER_POINT_STATES NONE +#include __FILE__ // IWYU pragma: keep +#undef SW_RASTER_POINT_STATES - // Single source of truth for all rasterizer specializations - // X(NAME, STATE_FLAGS) - #define SW_RASTER_VARIANTS(X) \ - X(BASE, 0) \ - X(DEPTH, SW_STATE_DEPTH_TEST) \ - X(BLEND, SW_STATE_BLEND) \ - X(DEPTH_BLEND, SW_STATE_DEPTH_TEST | SW_STATE_BLEND) +#define SW_RASTER_POINT_STATES DEPTH_TEST +#include __FILE__ +#undef SW_RASTER_POINT_STATES - // Forward declarations because clangd does not follow #include __FILE__ to avoid infinite recursion - // These declarations make all variants visible to static analysis tools without affecting compilation - #define SW_FWD_DECL(NAME, _FLAGS) \ - static void sw_raster_point_##NAME(const sw_vertex_t *v); - SW_RASTER_VARIANTS(SW_FWD_DECL) // NOLINT - #undef SW_FWD_DECL +#define SW_RASTER_POINT_STATES BLEND +#include __FILE__ +#undef SW_RASTER_POINT_STATES - // Specialization generation via self-inclusion +#define SW_RASTER_POINT_STATES DEPTH_TEST, BLEND +#include __FILE__ +#undef SW_RASTER_POINT_STATES - #define RLSW_TEMPLATE_RASTER_POINT BASE - #include __FILE__ // IWYU pragma: keep - #undef RLSW_TEMPLATE_RASTER_POINT +// Forward declarations for static analyzer like clangd that do not handle self-inclusion correctly +SW_RASTER_VARIANTS_2(SW_RASTER_FWD, sw_raster_point_, (const sw_vertex_t*)) // NOLINT - #define RLSW_TEMPLATE_RASTER_POINT DEPTH - #define SW_ENABLE_DEPTH_TEST - #include __FILE__ - #undef SW_ENABLE_DEPTH_TEST - #undef RLSW_TEMPLATE_RASTER_POINT - - #define RLSW_TEMPLATE_RASTER_POINT BLEND - #define SW_ENABLE_BLEND - #include __FILE__ - #undef SW_ENABLE_BLEND - #undef RLSW_TEMPLATE_RASTER_POINT - - #define RLSW_TEMPLATE_RASTER_POINT DEPTH_BLEND - #define SW_ENABLE_DEPTH_TEST - #define SW_ENABLE_BLEND - #include __FILE__ - #undef SW_ENABLE_BLEND - #undef SW_ENABLE_DEPTH_TEST - #undef RLSW_TEMPLATE_RASTER_POINT - - // Dispatch table (auto-generated from SW_RASTER_VARIANTS) - #define SW_TABLE_ENTRY(NAME, FLAGS) [FLAGS] = sw_raster_point_##NAME, - static const sw_raster_point_f SW_RASTER_POINT_TABLE[] = { - SW_RASTER_VARIANTS(SW_TABLE_ENTRY) - }; - #undef SW_TABLE_ENTRY - -#undef SW_RASTER_VARIANTS -#undef RLSW_TEMPLATE_RASTER_POINT_EXPANDING - -#endif // RLSW_TEMPLATE_RASTER_POINT_EXPANDING +static const sw_raster_point_f SW_RASTER_POINT_TABLE[] = { + SW_RASTER_VARIANTS_2(SW_RASTER_ENTRY, sw_raster_point_) +}; //------------------------------------------------------------------------------------------- // Triangle rendering logic @@ -3777,17 +3665,8 @@ static bool sw_line_clip_and_project(sw_vertex_t *v0, sw_vertex_t *v1) static void sw_line_render(uint32_t state, sw_vertex_t *vertices) { if (!sw_line_clip_and_project(&vertices[0], &vertices[1])) return; - state &= SW_RASTER_LINE_STATE_MASK; - - if (RLSW.lineWidth >= 2.0f) - { - SW_RASTER_LINE_THICK_TABLE[state](&vertices[0], &vertices[1]); - } - else - { - SW_RASTER_LINE_TABLE[state](&vertices[0], &vertices[1]); - } + SW_RASTER_LINE_TABLE[state](&vertices[0], &vertices[1]); } //------------------------------------------------------------------------------------------- @@ -3923,7 +3802,6 @@ static void sw_immediate_set_color(const float color[4]) RLSW.primitive.color[1] = color[1]; RLSW.primitive.color[2] = color[2]; RLSW.primitive.color[3] = color[3]; - } static void sw_immediate_set_texcoord(const float texcoord[2]) @@ -3980,6 +3858,18 @@ static void sw_immediate_push_vertex(const float position[4]) } } + // Determine whether colors should be interpolated + const float *ref = RLSW.primitive.buffer[0].color; + for (int i = 1; i < RLSW.primitive.vertexCount; ++i) + { + const float *c = RLSW.primitive.buffer[i].color; + if (c[0] != ref[0] || c[1] != ref[1] || c[2] != ref[2] || c[3] != ref[3]) + { + state |= SW_STATE_COLOR_INTERP; + break; + } + } + switch (RLSW.polyMode) { case SW_FILL: sw_poly_fill_render(state); break; @@ -5390,29 +5280,85 @@ void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWattachget // Triangle rasterization functions //------------------------------------------------------------------------------------------- -#ifdef RLSW_TEMPLATE_RASTER_TRIANGLE +#ifdef SW_RASTER_TRIANGLE_STATES -// Options: -// - RLSW_TEMPLATE_RASTER_TRIANGLE -> Contains the suffix name -// - SW_ENABLE_DEPTH_TEST -// - SW_ENABLE_TEXTURE -// - SW_ENABLE_BLEND +#define SW_RASTER_TRIANGLE_FLAGS SW_FLAGS(SW_RASTER_TRIANGLE_STATES) +#define SW_RASTER_TRIANGLE_SPAN SW_CONCATX(sw_raster_triangle_span_, SW_NAME(SW_RASTER_TRIANGLE_STATES)) +#define SW_RASTER_TRIANGLE SW_CONCATX(sw_raster_triangle_, SW_NAME(SW_RASTER_TRIANGLE_STATES)) +#define SW_SPAN_CTX SW_CONCATX(sw_span_ctx_, SW_NAME(SW_RASTER_TRIANGLE_STATES)) -#define SW_RASTER_TRIANGLE_SPAN SW_CONCATX(sw_raster_triangle_span_, RLSW_TEMPLATE_RASTER_TRIANGLE) -#define SW_RASTER_TRIANGLE SW_CONCATX(sw_raster_triangle_, RLSW_TEMPLATE_RASTER_TRIANGLE) +// True when a perspective-correct interpolation pass is needed (color or UVs); +// lets SPAN skip all w-tracking and block subdivision otherwise +#define SW_RASTER_TRIANGLE_NEEDS_PERSPECTIVE \ + (((SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_COLOR_INTERP) || ((SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_TEXTURE_2D)) -#ifdef SW_ENABLE_TEXTURE - #define SW_GET_GRAD sw_get_vertex_grad_PCT - #define SW_ADD_GRAD sw_add_vertex_grad_PCT - #define SW_ADD_GRAD_SCALED sw_add_vertex_grad_scaled_PCT -#else - #define SW_GET_GRAD sw_get_vertex_grad_PC - #define SW_ADD_GRAD sw_add_vertex_grad_PC - #define SW_ADD_GRAD_SCALED sw_add_vertex_grad_scaled_PC -#endif +#define SW_GRAD SW_CONCATX(sw_grad_, SW_NAME(SW_RASTER_TRIANGLE_STATES)) +#define SW_VADD SW_CONCATX(sw_vadd_, SW_NAME(SW_RASTER_TRIANGLE_STATES)) +#define SW_VMAD SW_CONCATX(sw_vmad_, SW_NAME(SW_RASTER_TRIANGLE_STATES)) -static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t *end, float dUdy, float dVdy) +// Per-triangle constants reused by every scanline: attribute x-derivatives +// (constant across a planar triangle) plus whatever is fixed once and for +// all when its interpolation is disabled (flat color, resolved sampler) +typedef struct { +#if SW_RASTER_TRIANGLE_NEEDS_PERSPECTIVE + float dWdx; +#endif +#if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_DEPTH_TEST + float dZdx; +#endif +#if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_COLOR_INTERP + float dCdx[4]; +#else + float flatColor[4]; +#endif +#if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_TEXTURE_2D + float dTdx[2]; + float dTdy[2]; + sw_texture_sampler_f sample; +#endif +} SW_SPAN_CTX; + +static inline void SW_GRAD(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float scale) +{ + SW_VEC_OP(out->position[i] = (b->position[i] - a->position[i])*scale, i, 4); +#if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_COLOR_INTERP + SW_VEC_OP(out->color[i] = (b->color[i] - a->color[i])*scale, i, 4); +#endif +#if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_TEXTURE_2D + SW_VEC_OP(out->texcoord[i] = (b->texcoord[i] - a->texcoord[i])*scale, i, 2); +#endif +} + +static inline void SW_VADD(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT inc) +{ + SW_VEC_OP(out->position[i] += inc->position[i], i, 4); +#if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_COLOR_INTERP + SW_VEC_OP(out->color[i] += inc->color[i], i, 4); +#endif +#if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_TEXTURE_2D + SW_VEC_OP(out->texcoord[i] += inc->texcoord[i], i, 2); +#endif +} + +static inline void SW_VMAD(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT inc, float scale) +{ + SW_VEC_OP(out->position[i] += inc->position[i]*scale, i, 4); +#if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_COLOR_INTERP + SW_VEC_OP(out->color[i] += inc->color[i]*scale, i, 4); +#endif +#if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_TEXTURE_2D + SW_VEC_OP(out->texcoord[i] += inc->texcoord[i]*scale, i, 2); +#endif +} + +static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t *end, const SW_SPAN_CTX *ctx) +{ + // Skip rows outside the framebuffer; can only trigger on FP rounding at + // clip boundaries since triangles are already clipped to the viewport + int y = (int)start->position[1]; + if (y < 0 || y >= RLSW.colorBuffer->height) return; + // Gets the start/end coordinates and skip empty lines int xStart = (int)start->position[0]; int xEnd = (int)end->position[0]; @@ -5423,64 +5369,44 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t int xLoopEnd = (xEnd <= RLSW.colorBuffer->width)? xEnd : RLSW.colorBuffer->width; if (xLoopStart >= xLoopEnd) return; // Nothing to draw - // Get the current row and skip if outside the framebuffer - // Maybe this check is better suited elsewhere? - int y = (int)start->position[1]; - if (y < 0 || y >= RLSW.colorBuffer->height) return; - - // Compute the inverse horizontal distance along the X axis - float dxRcp = sw_rcp(end->position[0] - start->position[0]); - - // Compute the interpolation steps along the X axis - float dWdx = (end->position[3] - start->position[3])*dxRcp; - float dCdx[4] = { - (end->color[0] - start->color[0])*dxRcp, - (end->color[1] - start->color[1])*dxRcp, - (end->color[2] - start->color[2])*dxRcp, - (end->color[3] - start->color[3])*dxRcp - }; -#ifdef SW_ENABLE_DEPTH_TEST - float dZdx = (end->position[2] - start->position[2])*dxRcp; -#endif -#ifdef SW_ENABLE_TEXTURE - float dUdx = (end->texcoord[0] - start->texcoord[0])*dxRcp; - float dVdx = (end->texcoord[1] - start->texcoord[1])*dxRcp; -#endif - // Compute the subpixel distance to traverse before the first pixel // Also step further into them to move away from the colorbuffer edge float xSubstep = 1.0f - sw_fract(start->position[0]); float dxStart = (float)(xLoopStart - xStart); float xOffset = xSubstep + dxStart; - // Initializing the interpolation starting values - float w = start->position[3] + dWdx*xOffset; - float color[4] = { - start->color[0] + dCdx[0]*xOffset, - start->color[1] + dCdx[1]*xOffset, - start->color[2] + dCdx[2]*xOffset, - start->color[3] + dCdx[3]*xOffset - }; -#ifdef SW_ENABLE_DEPTH_TEST - float z = start->position[2] + dZdx*xOffset; -#endif -#ifdef SW_ENABLE_TEXTURE - float u = start->texcoord[0] + dUdx*xOffset; - float v = start->texcoord[1] + dVdx*xOffset; -#endif - // Pre-calculate the starting pointers for the framebuffer row int baseOffset = y*RLSW.colorBuffer->width + xLoopStart; uint8_t *cPtr = (uint8_t *)(RLSW.colorBuffer->pixels) + baseOffset*SW_FRAMEBUFFER_COLOR_SIZE; -#ifdef SW_ENABLE_DEPTH_TEST +#if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_DEPTH_TEST uint8_t *dPtr = (uint8_t *)(RLSW.depthBuffer->pixels) + baseOffset*SW_FRAMEBUFFER_DEPTH_SIZE; #endif + // Initializing the interpolation starting values +#if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_DEPTH_TEST + float z = start->position[2] + ctx->dZdx*xOffset; +#endif +#if SW_RASTER_TRIANGLE_NEEDS_PERSPECTIVE + float w = start->position[3] + ctx->dWdx*xOffset; +#endif +#if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_COLOR_INTERP + float color[4]; + SW_VEC_OP(color[i] = start->color[i] + ctx->dCdx[i]*xOffset, i, 4); +#else + // Flat: constant across the whole triangle, computed once for the whole span + const float *srcColor = ctx->flatColor; +#endif +#if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_TEXTURE_2D + float texcoord[2]; + SW_VEC_OP(texcoord[i] = start->texcoord[i] + ctx->dTdx[i]*xOffset, i, 2); +#endif + #define SW_AFFINE_BLOCK 16 int x = xLoopStart; while (x < xLoopEnd) { + #if SW_RASTER_TRIANGLE_NEEDS_PERSPECTIVE // Clamp last block to remaining pixels int blockEnd = x + SW_AFFINE_BLOCK; if (blockEnd > xLoopEnd) blockEnd = xLoopEnd; @@ -5489,112 +5415,87 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t // Only 2 '1/w' here; none inside the pixel loop float wRcpA = sw_rcp(w); - float wB = w + dWdx*blockLenF; + float wB = w + ctx->dWdx*blockLenF; float wRcpB = sw_rcp(wB); + #else + // Nothing perspective-correct to interpolate: one block covers the whole span + int blockEnd = xLoopEnd; + #endif + #if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_COLOR_INTERP // Perspective-correct color at both block endpoints, then affine gradient - float srcColor[4] = { - color[0]*wRcpA, - color[1]*wRcpA, - color[2]*wRcpA, - color[3]*wRcpA - }; - float dSrcColordx[4] = { - ((color[0] + dCdx[0]*blockLenF)*wRcpB - srcColor[0])*blockLenRcp, - ((color[1] + dCdx[1]*blockLenF)*wRcpB - srcColor[1])*blockLenRcp, - ((color[2] + dCdx[2]*blockLenF)*wRcpB - srcColor[2])*blockLenRcp, - ((color[3] + dCdx[3]*blockLenF)*wRcpB - srcColor[3])*blockLenRcp - }; + float srcColor[4], dSrcColor[4]; + SW_VEC_OP(srcColor[i] = color[i]*wRcpA, i, 4); + SW_VEC_OP(dSrcColor[i] = ((color[i] + ctx->dCdx[i]*blockLenF)*wRcpB - srcColor[i])*blockLenRcp, i, 4); + #endif - #ifdef SW_ENABLE_TEXTURE + #if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_TEXTURE_2D // Perspective-correct UVs at both endpoints, then affine gradient - float uAffine = u*wRcpA; - float vAffine = v*wRcpA; - float dUaffine = ((u + dUdx*blockLenF)*wRcpB - uAffine)*blockLenRcp; - float dVaffine = ((v + dVdx*blockLenF)*wRcpB - vAffine)*blockLenRcp; + float tcAffine[2], dTcAffine[2]; + SW_VEC_OP(tcAffine[i] = texcoord[i]*wRcpA, i, 2); + SW_VEC_OP(dTcAffine[i] = ((texcoord[i] + ctx->dTdx[i]*blockLenF)*wRcpB - tcAffine[i])*blockLenRcp, i, 2); #endif // Inner span pixel loop for (; x < blockEnd; x++) { - #ifdef SW_ENABLE_DEPTH_TEST + #if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_DEPTH_TEST + float depth = SW_FRAMEBUFFER_DEPTH_GET(dPtr, 0); + if (z <= depth) { - float depth = SW_FRAMEBUFFER_DEPTH_GET(dPtr, 0); - if (z > depth) goto discard; SW_FRAMEBUFFER_DEPTH_SET(dPtr, z, 0); - } + #endif + + #if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_TEXTURE_2D + float finalColor[4]; + ctx->sample(finalColor, RLSW.boundTexture, tcAffine[0], tcAffine[1]); + SW_VEC_OP(finalColor[i] *= srcColor[i], i, 4); + #define SW_FINAL_COLOR finalColor + #else + #define SW_FINAL_COLOR srcColor #endif - #ifdef SW_ENABLE_TEXTURE + #if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_BLEND { - float texColor[4]; - sw_texture_sample(texColor, RLSW.boundTexture, uAffine, vAffine, dUdx, dUdy, dVdx, dVdy); - float finalColor[4] = { - srcColor[0]*texColor[0], - srcColor[1]*texColor[1], - srcColor[2]*texColor[2], - srcColor[3]*texColor[3] - }; - #ifdef SW_ENABLE_BLEND - { - float dstColor[4]; - SW_FRAMEBUFFER_COLOR_GET(dstColor, cPtr, 0); - RLSW.blendFunc(dstColor, finalColor); - SW_FRAMEBUFFER_COLOR_SET(cPtr, dstColor, 0); - } - #else - SW_FRAMEBUFFER_COLOR_SET(cPtr, finalColor, 0); - #endif + float dstColor[4]; + SW_FRAMEBUFFER_COLOR_GET(dstColor, cPtr, 0); + RLSW.blendFunc(dstColor, SW_FINAL_COLOR); + SW_FRAMEBUFFER_COLOR_SET(cPtr, dstColor, 0); } #else - { - #ifdef SW_ENABLE_BLEND - { - float dstColor[4]; - SW_FRAMEBUFFER_COLOR_GET(dstColor, cPtr, 0); - RLSW.blendFunc(dstColor, srcColor); - SW_FRAMEBUFFER_COLOR_SET(cPtr, dstColor, 0); - } - #else - SW_FRAMEBUFFER_COLOR_SET(cPtr, srcColor, 0); - #endif - } + SW_FRAMEBUFFER_COLOR_SET(cPtr, SW_FINAL_COLOR, 0); #endif - #ifdef SW_ENABLE_DEPTH_TEST - discard: + #undef SW_FINAL_COLOR + + #if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_DEPTH_TEST + } #endif - srcColor[0] += dSrcColordx[0]; - srcColor[1] += dSrcColordx[1]; - srcColor[2] += dSrcColordx[2]; - srcColor[3] += dSrcColordx[3]; + + // Advance unconditionally: depth test only guards the write above cPtr += SW_FRAMEBUFFER_COLOR_SIZE; - - #ifdef SW_ENABLE_DEPTH_TEST - { - z += dZdx; - dPtr += SW_FRAMEBUFFER_DEPTH_SIZE; - } - #endif - - #ifdef SW_ENABLE_TEXTURE - { - uAffine += dUaffine; - vAffine += dVaffine; - } - #endif + #if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_DEPTH_TEST + dPtr += SW_FRAMEBUFFER_DEPTH_SIZE; + z += ctx->dZdx; + #endif + #if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_COLOR_INTERP + SW_VEC_OP(srcColor[i] += dSrcColor[i], i, 4); + #endif + #if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_TEXTURE_2D + SW_VEC_OP(tcAffine[i] += dTcAffine[i], i, 2); + #endif } +#if SW_RASTER_TRIANGLE_NEEDS_PERSPECTIVE // Advance perspective-space accumulators by the full block width w = wB; - color[0] += dCdx[0]*blockLenF; - color[1] += dCdx[1]*blockLenF; - color[2] += dCdx[2]*blockLenF; - color[3] += dCdx[3]*blockLenF; - #ifdef SW_ENABLE_TEXTURE - u += dUdx*blockLenF; - v += dVdx*blockLenF; - #endif + #if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_COLOR_INTERP + SW_VEC_OP(color[i] += ctx->dCdx[i]*blockLenF, i, 4); + #endif + #if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_TEXTURE_2D + SW_VEC_OP(texcoord[i] += ctx->dTdx[i]*blockLenF, i, 2); + #endif +#endif } #undef SW_AFFINE_BLOCK @@ -5617,18 +5518,52 @@ static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, con float h01 = y1 - y0; float h12 = y2 - y1; - if (h02 < 1e-6f) return; + if (h02 < 1e-6f) return; // Degenerate (zero screen height): nothing to rasterize // Inverse edge dy for per-edge dV/dy (scanline interpolation) float h02Rcp = sw_rcp(h02); float h01Rcp = (h01 > 1e-6f)? sw_rcp(h01) : 0.0f; float h12Rcp = (h12 > 1e-6f)? sw_rcp(h12) : 0.0f; + // D = twice the signed screen area; also the shared denominator of the + // barycentric plane solve used below for whole-triangle x/y derivatives + float e1x = v1->position[0] - v0->position[0]; + float e2x = v2->position[0] - v0->position[0]; + float D = e1x*h02 - e2x*h01; + if (fabsf(D) < 1e-9f) return; // Degenerate (zero screen area): nothing to rasterize + float DRcp = sw_rcp(D); + + // Whole-triangle xy-derivatives of an affine attribute (constant for every scanline) + #define SW_DADX(A0, A1, A2) ((((A1)-(A0))*h02 - ((A2)-(A0))*h01)*DRcp) + #define SW_DADY(A0, A1, A2) ((((A2)-(A0))*e1x - ((A1)-(A0))*e2x)*DRcp) + + SW_SPAN_CTX ctx; +#if SW_RASTER_TRIANGLE_NEEDS_PERSPECTIVE + ctx.dWdx = SW_DADX(v0->position[3], v1->position[3], v2->position[3]); +#endif +#if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_DEPTH_TEST + ctx.dZdx = SW_DADX(v0->position[2], v1->position[2], v2->position[2]); +#endif +#if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_COLOR_INTERP + SW_VEC_OP(ctx.dCdx[i] = SW_DADX(v0->color[i], v1->color[i], v2->color[i]), i, 4); +#else + float flatWRcp = sw_rcp(v0->position[3]); + SW_VEC_OP(ctx.flatColor[i] = v0->color[i]*flatWRcp, i, 4); +#endif +#if (SW_RASTER_TRIANGLE_FLAGS) & SW_STATE_TEXTURE_2D + SW_VEC_OP(ctx.dTdx[i] = SW_DADX(v0->texcoord[i], v1->texcoord[i], v2->texcoord[i]), i, 2); + SW_VEC_OP(ctx.dTdy[i] = SW_DADY(v0->texcoord[i], v1->texcoord[i], v2->texcoord[i]), i, 2); + ctx.sample = sw_texture_pick_sampler(RLSW.boundTexture, ctx.dTdx, ctx.dTdy); +#endif + + #undef SW_DADX + #undef SW_DADY + // Compute gradients for each side of the triangle sw_vertex_t dVXdy02, dVXdy01, dVXdy12; - SW_GET_GRAD(&dVXdy02, v0, v2, h02Rcp); - SW_GET_GRAD(&dVXdy01, v0, v1, h01Rcp); - SW_GET_GRAD(&dVXdy12, v1, v2, h12Rcp); + SW_GRAD(&dVXdy02, v0, v2, h02Rcp); + SW_GRAD(&dVXdy01, v0, v1, h01Rcp); + SW_GRAD(&dVXdy12, v1, v2, h12Rcp); // Y subpixel correction float y0Substep = 1.0f - sw_fract(y0); @@ -5636,8 +5571,8 @@ static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, con // Get a copy of vertices for interpolation and apply substep correction sw_vertex_t lVert = *v0, rVert = *v0; - SW_ADD_GRAD_SCALED(&lVert, &dVXdy02, y0Substep); - SW_ADD_GRAD_SCALED(&rVert, &dVXdy01, y0Substep); + SW_VMAD(&lVert, &dVXdy02, y0Substep); + SW_VMAD(&rVert, &dVXdy01, y0Substep); // Y bounds (vertical clipping) int yTop = (int)y0; @@ -5651,14 +5586,14 @@ static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, con bool longSideIsLeft = (lVert.position[0] < rVert.position[0]); const sw_vertex_t *a = longSideIsLeft? &lVert : &rVert; const sw_vertex_t *b = longSideIsLeft? &rVert : &lVert; - SW_RASTER_TRIANGLE_SPAN(a, b, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); - SW_ADD_GRAD(&lVert, &dVXdy02); - SW_ADD_GRAD(&rVert, &dVXdy01); + SW_RASTER_TRIANGLE_SPAN(a, b, &ctx); + SW_VADD(&lVert, &dVXdy02); + SW_VADD(&rVert, &dVXdy01); } // Get a copy of next right for interpolation and apply substep correction rVert = *v1; - SW_ADD_GRAD_SCALED(&rVert, &dVXdy12, y1Substep); + SW_VMAD(&rVert, &dVXdy12, y1Substep); // Scanline for the lower part of the triangle for (int y = yMid; y < yBot; y++) @@ -5667,30 +5602,21 @@ static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, con bool longSideIsLeft = (lVert.position[0] < rVert.position[0]); const sw_vertex_t *a = longSideIsLeft? &lVert : &rVert; const sw_vertex_t *b = longSideIsLeft? &rVert : &lVert; - SW_RASTER_TRIANGLE_SPAN(a, b, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); - SW_ADD_GRAD(&lVert, &dVXdy02); - SW_ADD_GRAD(&rVert, &dVXdy12); + SW_RASTER_TRIANGLE_SPAN(a, b, &ctx); + SW_VADD(&lVert, &dVXdy02); + SW_VADD(&rVert, &dVXdy12); } } -#undef SW_GET_GRAD -#undef SW_ADD_GRAD -#undef SW_ADD_GRAD_SCALED - -#endif // RLSW_TEMPLATE_RASTER_TRIANGLE +#endif // SW_RASTER_TRIANGLE_STATES //------------------------------------------------------------------------------------------- // Quad rasterization functions //------------------------------------------------------------------------------------------- -#ifdef RLSW_TEMPLATE_RASTER_QUAD +#ifdef SW_RASTER_QUAD_STATES -// Options: -// - RLSW_TEMPLATE_RASTER_QUAD -> Contains the suffix name -// - SW_ENABLE_DEPTH_TEST -// - SW_ENABLE_TEXTURE -// - SW_ENABLE_BLEND - -#define SW_RASTER_QUAD SW_CONCATX(sw_raster_quad_, RLSW_TEMPLATE_RASTER_QUAD) +#define SW_RASTER_QUAD_FLAGS SW_FLAGS(SW_RASTER_QUAD_STATES) +#define SW_RASTER_QUAD SW_CONCATX(sw_raster_quad_, SW_NAME(SW_RASTER_QUAD_STATES)) // NOTE: This function should only render affine axis-aligned quads // No perspective divide is applied after interpolation @@ -5702,14 +5628,18 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b, // For axis-aligned quads x+y and x-y uniquely identify each corner const sw_vertex_t *verts[4] = { a, b, c, d }; const sw_vertex_t *tl = verts[0], *tr = verts[0], *br = verts[0], *bl = verts[0]; + float tlSum = tl->position[0] + tl->position[1]; + float trDiff = tr->position[0] - tr->position[1]; + float brSum = br->position[0] + br->position[1]; + float blDiff = bl->position[0] - bl->position[1]; for (int i = 1; i < 4; i++) { float sum = verts[i]->position[0] + verts[i]->position[1]; float diff = verts[i]->position[0] - verts[i]->position[1]; - if (sum < tl->position[0] + tl->position[1]) tl = verts[i]; - if (diff > tr->position[0] - tr->position[1]) tr = verts[i]; - if (sum > br->position[0] + br->position[1]) br = verts[i]; - if (diff < bl->position[0] - bl->position[1]) bl = verts[i]; + if (sum < tlSum) { tl = verts[i]; tlSum = sum; } + if (diff > trDiff) { tr = verts[i]; trDiff = diff; } + if (sum > brSum) { br = verts[i]; brSum = sum; } + if (diff < blDiff) { bl = verts[i]; blDiff = diff; } } int xMin = (int)tl->position[0]; @@ -5729,150 +5659,121 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b, float h = (float)(yMax - yMin); if ((w <= 0) || (h <= 0)) return; + // Per-quad setup, independent of pipeline state float wRcp = sw_rcp(w); float hRcp = sw_rcp(h); - - // Subpixel corrections float xSubstep = 1.0f - sw_fract(tl->position[0]); float ySubstep = 1.0f - sw_fract(tl->position[1]); - - // Gradients along X (tl->tr) and Y (tl->bl) - float dCdx[4] = { - (tr->color[0] - tl->color[0])*wRcp, - (tr->color[1] - tl->color[1])*wRcp, - (tr->color[2] - tl->color[2])*wRcp, - (tr->color[3] - tl->color[3])*wRcp, - }; - float dCdy[4] = { - (bl->color[0] - tl->color[0])*hRcp, - (bl->color[1] - tl->color[1])*hRcp, - (bl->color[2] - tl->color[2])*hRcp, - (bl->color[3] - tl->color[3])*hRcp, - }; - -#ifdef SW_ENABLE_DEPTH_TEST - float dZdx = (tr->position[2] - tl->position[2])*wRcp; - float dZdy = (bl->position[2] - tl->position[2])*hRcp; - float zRow = tl->position[2] + dZdx*xSubstep + dZdy*ySubstep; -#endif - -#ifdef SW_ENABLE_TEXTURE - float dUdx = (tr->texcoord[0] - tl->texcoord[0])*wRcp; - float dVdx = (tr->texcoord[1] - tl->texcoord[1])*wRcp; - float dUdy = (bl->texcoord[0] - tl->texcoord[0])*hRcp; - float dVdy = (bl->texcoord[1] - tl->texcoord[1])*hRcp; - float uRow = tl->texcoord[0] + dUdx*xSubstep + dUdy*ySubstep; - float vRow = tl->texcoord[1] + dVdx*xSubstep + dVdy*ySubstep; -#endif - - float cRow[4] = { - tl->color[0] + dCdx[0]*xSubstep + dCdy[0]*ySubstep, - tl->color[1] + dCdx[1]*xSubstep + dCdy[1]*ySubstep, - tl->color[2] + dCdx[2]*xSubstep + dCdy[2]*ySubstep, - tl->color[3] + dCdx[3]*xSubstep + dCdy[3]*ySubstep, - }; - + // Distance the in-bounds boundary is from the quad's edges, only on the left and top + float dxMin = (float)(xLoopMin - xMin); + float dyMin = (float)(yLoopMin - yMin); int stride = RLSW.colorBuffer->width; uint8_t *cPixels = RLSW.colorBuffer->pixels; -#ifdef SW_ENABLE_DEPTH_TEST +#if (SW_RASTER_QUAD_FLAGS) & SW_STATE_DEPTH_TEST uint8_t *dPixels = RLSW.depthBuffer->pixels; #endif - // Calculate the distance the in-bounds boundary is from the quad's edges, only on the left and top - float dxMin = (float)(xLoopMin - xMin); - float dyMin = (float)(yLoopMin - yMin); - - // Correct our start by how far it's clipped outside the framebuffer - cRow[0] += dCdx[0]*dxMin + dCdy[0]*dyMin; - cRow[1] += dCdx[1]*dxMin + dCdy[1]*dyMin; - cRow[2] += dCdx[2]*dxMin + dCdy[2]*dyMin; - cRow[3] += dCdx[3]*dxMin + dCdy[3]*dyMin; - #ifdef SW_ENABLE_DEPTH_TEST +#if (SW_RASTER_QUAD_FLAGS) & SW_STATE_DEPTH_TEST + // Gradients along X (tl->tr) and Y (tl->bl) + float dZdx = (tr->position[2] - tl->position[2])*wRcp; + float dZdy = (bl->position[2] - tl->position[2])*hRcp; + float zRow = tl->position[2] + dZdx*xSubstep + dZdy*ySubstep; + // Correct start by how far it's clipped outside the framebuffer zRow += dZdy*dyMin + dZdx*dxMin; - #endif - #ifdef SW_ENABLE_TEXTURE - uRow += dUdy*dyMin + dUdx*dxMin; - vRow += dVdy*dyMin + dVdx*dxMin; - #endif +#endif + +#if (SW_RASTER_QUAD_FLAGS) & SW_STATE_COLOR_INTERP + float dCdx[4], dCdy[4], cRow[4]; + SW_VEC_OP(dCdx[i] = (tr->color[i] - tl->color[i])*wRcp, i, 4); + SW_VEC_OP(dCdy[i] = (bl->color[i] - tl->color[i])*hRcp, i, 4); + SW_VEC_OP(cRow[i] = tl->color[i] + dCdx[i]*xSubstep + dCdy[i]*ySubstep, i, 4); + SW_VEC_OP(cRow[i] += dCdx[i]*dxMin + dCdy[i]*dyMin, i, 4); +#else + const float *flatColor = tl->color; +#endif + +#if (SW_RASTER_QUAD_FLAGS) & SW_STATE_TEXTURE_2D + float dTdx[2], dTdy[2], tcRow[2]; + SW_VEC_OP(dTdx[i] = (tr->texcoord[i] - tl->texcoord[i])*wRcp, i, 2); + SW_VEC_OP(dTdy[i] = (bl->texcoord[i] - tl->texcoord[i])*hRcp, i, 2); + SW_VEC_OP(tcRow[i] = tl->texcoord[i] + dTdx[i]*xSubstep + dTdy[i]*ySubstep, i, 2); + SW_VEC_OP(tcRow[i] += dTdy[i]*dyMin + dTdx[i]*dxMin, i, 2); + + // Constant across the whole quad: resolved once, called directly per pixel + sw_texture_sampler_f sample = sw_texture_pick_sampler(RLSW.boundTexture, dTdx, dTdy); +#endif for (int y = yLoopMin; y < yLoopMax; y++) { int baseOffset = y*stride + xLoopMin; uint8_t *cPtr = cPixels + baseOffset*SW_FRAMEBUFFER_COLOR_SIZE; - #ifdef SW_ENABLE_DEPTH_TEST + #if (SW_RASTER_QUAD_FLAGS) & SW_STATE_DEPTH_TEST uint8_t *dPtr = dPixels + baseOffset*SW_FRAMEBUFFER_DEPTH_SIZE; - // Copy the cursors without destroying the offset maths float z = zRow; #endif - #ifdef SW_ENABLE_TEXTURE - float u = uRow; - float v = vRow; + #if (SW_RASTER_QUAD_FLAGS) & SW_STATE_TEXTURE_2D + float tc[2] = { tcRow[0], tcRow[1] }; + #endif + #if (SW_RASTER_QUAD_FLAGS) & SW_STATE_COLOR_INTERP + float color[4] = { cRow[0], cRow[1], cRow[2], cRow[3] }; #endif - float color[4] = { - cRow[0], - cRow[1], - cRow[2], - cRow[3] - }; for (int x = xLoopMin; x < xLoopMax; x++) { - float srcColor[4] = { color[0], color[1], color[2], color[3] }; + #if (SW_RASTER_QUAD_FLAGS) & SW_STATE_COLOR_INTERP + #define SW_QUAD_BASE_COLOR color + #else + #define SW_QUAD_BASE_COLOR flatColor + #endif - #ifdef SW_ENABLE_DEPTH_TEST + #if (SW_RASTER_QUAD_FLAGS) & SW_STATE_TEXTURE_2D + // Mutable copy: about to be modulated by the sampled texel below + float srcColor[4]; + SW_VEC_OP(srcColor[i] = SW_QUAD_BASE_COLOR[i], i, 4); + #else + // Never mutated past this point: alias directly, no copy needed + const float *srcColor = SW_QUAD_BASE_COLOR; + #endif + + #if (SW_RASTER_QUAD_FLAGS) & SW_STATE_DEPTH_TEST + float depth = SW_FRAMEBUFFER_DEPTH_GET(dPtr, 0); + if (z <= depth) { - float depth = SW_FRAMEBUFFER_DEPTH_GET(dPtr, 0); - if (z > depth) goto discard; SW_FRAMEBUFFER_DEPTH_SET(dPtr, z, 0); - } - #endif + #endif - #ifdef SW_ENABLE_TEXTURE - { + #if (SW_RASTER_QUAD_FLAGS) & SW_STATE_TEXTURE_2D float texColor[4]; - sw_texture_sample(texColor, RLSW.boundTexture, u, v, dUdx, dUdy, dVdx, dVdy); - srcColor[0] *= texColor[0]; - srcColor[1] *= texColor[1]; - srcColor[2] *= texColor[2]; - srcColor[3] *= texColor[3]; - } + sample(texColor, RLSW.boundTexture, tc[0], tc[1]); + SW_VEC_OP(srcColor[i] *= texColor[i], i, 4); #endif - #ifdef SW_ENABLE_BLEND - { + #if (SW_RASTER_QUAD_FLAGS) & SW_STATE_BLEND float dstColor[4]; SW_FRAMEBUFFER_COLOR_GET(dstColor, cPtr, 0); RLSW.blendFunc(dstColor, srcColor); SW_FRAMEBUFFER_COLOR_SET(cPtr, dstColor, 0); - } #else - { SW_FRAMEBUFFER_COLOR_SET(cPtr, srcColor, 0); - } #endif - #ifdef SW_ENABLE_DEPTH_TEST - discard: + #if (SW_RASTER_QUAD_FLAGS) & SW_STATE_DEPTH_TEST + } #endif + // Move one pixel over without touching the original "start offset" - color[0] += dCdx[0]; - color[1] += dCdx[1]; - color[2] += dCdx[2]; - color[3] += dCdx[3]; + #if (SW_RASTER_QUAD_FLAGS) & SW_STATE_COLOR_INTERP + SW_VEC_OP(color[i] += dCdx[i], i, 4); + #endif - #ifdef SW_ENABLE_DEPTH_TEST - { - z += dZdx; - dPtr += SW_FRAMEBUFFER_DEPTH_SIZE; - } - #endif + #if (SW_RASTER_QUAD_FLAGS) & SW_STATE_DEPTH_TEST + z += dZdx; + dPtr += SW_FRAMEBUFFER_DEPTH_SIZE; + #endif - #ifdef SW_ENABLE_TEXTURE - { - u += dUdx; - v += dVdx; - } - #endif + #if (SW_RASTER_QUAD_FLAGS) & SW_STATE_TEXTURE_2D + SW_VEC_OP(tc[i] += dTdx[i], i, 2); + #endif cPtr += SW_FRAMEBUFFER_COLOR_SIZE; } @@ -5880,42 +5781,33 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b, // The for loop is clamped to the right side of the screen // However, these cursor start vars are still on the left // That's fine, advancing to the next row - cRow[0] += dCdy[0]; - cRow[1] += dCdy[1]; - cRow[2] += dCdy[2]; - cRow[3] += dCdy[3]; - - #ifdef SW_ENABLE_DEPTH_TEST - { - zRow += dZdy; - } - #endif - - #ifdef SW_ENABLE_TEXTURE - { - uRow += dUdy; - vRow += dVdy; - } - #endif + #if (SW_RASTER_QUAD_FLAGS) & SW_STATE_DEPTH_TEST + zRow += dZdy; + #endif + #if (SW_RASTER_QUAD_FLAGS) & SW_STATE_COLOR_INTERP + SW_VEC_OP(cRow[i] += dCdy[i], i, 4); + #endif + #if (SW_RASTER_QUAD_FLAGS) & SW_STATE_TEXTURE_2D + SW_VEC_OP(tcRow[i] += dTdy[i], i, 2); + #endif } + +#undef SW_QUAD_BASE_COLOR } -#endif // RLSW_TEMPLATE_RASTER_QUAD +#endif // SW_RASTER_QUAD_STATES //------------------------------------------------------------------------------------------- -// Quad rasterization functions +// Line rasterization functions //------------------------------------------------------------------------------------------- -#ifdef RLSW_TEMPLATE_RASTER_LINE +#ifdef SW_RASTER_LINE_STATES -// Options: -// - RLSW_TEMPLATE_RASTER_LINE -> Contains the suffix name -// - SW_ENABLE_DEPTH_TEST -// - SW_ENABLE_BLEND +#define SW_RASTER_LINE_FLAGS SW_FLAGS(SW_RASTER_LINE_STATES) +#define SW_RASTER_LINE_THIN SW_CONCATX(sw_raster_line_thin_, SW_NAME(SW_RASTER_LINE_STATES)) +#define SW_RASTER_LINE SW_CONCATX(sw_raster_line_, SW_NAME(SW_RASTER_LINE_STATES)) -#define SW_RASTER_LINE SW_CONCATX(sw_raster_line_, RLSW_TEMPLATE_RASTER_LINE) -#define SW_RASTER_LINE_THICK SW_CONCATX(sw_raster_line_thick_, RLSW_TEMPLATE_RASTER_LINE) - -static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1) +// Renders a single-pixel-wide line; internal building block for SW_RASTER_LINE +static void SW_RASTER_LINE_THIN(const sw_vertex_t *v0, const sw_vertex_t *v1) { // Convert from pixel-center convention (n+0.5) to pixel-origin convention (n) float x0 = v0->position[0] - 0.5f; @@ -5941,38 +5833,33 @@ static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1) substep = (dy >= 0.0f)? (1.0f - sw_fract(y0)) : sw_fract(y0); } - // Compute per pixel increments - float xInc = dx/steps; - float yInc = dy/steps; + // Line setup, independent of pipeline state float stepRcp = sw_rcp(steps); -#ifdef SW_ENABLE_DEPTH_TEST - float zInc = (v1->position[2] - v0->position[2])*stepRcp; + float xInc = dx*stepRcp; + float yInc = dy*stepRcp; + int numPixels = (int)(steps - substep) + 1; + const int fbWidth = RLSW.colorBuffer->width; + uint8_t *cPixels = RLSW.colorBuffer->pixels; +#if (SW_RASTER_LINE_FLAGS) & SW_STATE_DEPTH_TEST + uint8_t *dPixels = RLSW.depthBuffer->pixels; #endif - float rInc = (v1->color[0] - v0->color[0])*stepRcp; - float gInc = (v1->color[1] - v0->color[1])*stepRcp; - float bInc = (v1->color[2] - v0->color[2])*stepRcp; - float aInc = (v1->color[3] - v0->color[3])*stepRcp; // Initializing the interpolation starting values float x = x0 + xInc*substep; float y = y0 + yInc*substep; -#ifdef SW_ENABLE_DEPTH_TEST +#if (SW_RASTER_LINE_FLAGS) & SW_STATE_DEPTH_TEST + float zInc = (v1->position[2] - v0->position[2])*stepRcp; float z = v0->position[2] + zInc*substep; #endif - float r = v0->color[0] + rInc*substep; - float g = v0->color[1] + gInc*substep; - float b = v0->color[2] + bInc*substep; - float a = v0->color[3] + aInc*substep; - - // Start line rasterization - const int fbWidth = RLSW.colorBuffer->width; - uint8_t *cPixels = RLSW.colorBuffer->pixels; -#ifdef SW_ENABLE_DEPTH_TEST - uint8_t *dPixels = RLSW.depthBuffer->pixels; +#if (SW_RASTER_LINE_FLAGS) & SW_STATE_COLOR_INTERP + float cInc[4], color[4]; + SW_VEC_OP(cInc[i] = (v1->color[i] - v0->color[i])*stepRcp, i, 4); + SW_VEC_OP(color[i] = v0->color[i] + cInc[i]*substep, i, 4); +#else + // Flat: constant across the whole line, computed once for the whole loop + const float *srcColor = v0->color; #endif - int numPixels = (int)(steps - substep) + 1; - for (int i = 0; i < numPixels; i++) { int px = x; @@ -5980,55 +5867,56 @@ static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1) int baseOffset = py*fbWidth + px; uint8_t *cPtr = cPixels + baseOffset*SW_FRAMEBUFFER_COLOR_SIZE; - #ifdef SW_ENABLE_DEPTH_TEST + #if (SW_RASTER_LINE_FLAGS) & SW_STATE_DEPTH_TEST uint8_t *dPtr = dPixels + baseOffset*SW_FRAMEBUFFER_DEPTH_SIZE; #endif - #ifdef SW_ENABLE_DEPTH_TEST + #if (SW_RASTER_LINE_FLAGS) & SW_STATE_DEPTH_TEST + // TODO: Implement different depth funcs? + float depth = SW_FRAMEBUFFER_DEPTH_GET(dPtr, 0); + if (z <= depth) { - // TODO: Implement different depth funcs? - float depth = SW_FRAMEBUFFER_DEPTH_GET(dPtr, 0); - if (z > depth) goto discard; - // TODO: Implement depth mask SW_FRAMEBUFFER_DEPTH_SET(dPtr, z, 0); - } + #endif + + #if (SW_RASTER_LINE_FLAGS) & SW_STATE_COLOR_INTERP + const float *srcColor = color; #endif - float srcColor[4] = {r, g, b, a}; - - #ifdef SW_ENABLE_BLEND - { + #if (SW_RASTER_LINE_FLAGS) & SW_STATE_BLEND float dstColor[4]; SW_FRAMEBUFFER_COLOR_GET(dstColor, cPtr, 0); RLSW.blendFunc(dstColor, srcColor); SW_FRAMEBUFFER_COLOR_SET(cPtr, dstColor, 0); - } #else - { SW_FRAMEBUFFER_COLOR_SET(cPtr, srcColor, 0); - } #endif - #ifdef SW_ENABLE_DEPTH_TEST - discard: + #if (SW_RASTER_LINE_FLAGS) & SW_STATE_DEPTH_TEST + } #endif + + // Advance unconditionally: depth test only guards the write above x += xInc; y += yInc; - #ifdef SW_ENABLE_DEPTH_TEST - { - z += zInc; - } - #endif - r += rInc; - g += gInc; - b += bInc; - a += aInc; + #if (SW_RASTER_LINE_FLAGS) & SW_STATE_DEPTH_TEST + z += zInc; + #endif + #if (SW_RASTER_LINE_FLAGS) & SW_STATE_COLOR_INTERP + SW_VEC_OP(color[i] += cInc[i], i, 4); + #endif } } -static void SW_RASTER_LINE_THICK(const sw_vertex_t *v0, const sw_vertex_t *v1) +static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1) { + if (RLSW.lineWidth < 2.0f) + { + SW_RASTER_LINE_THIN(v0, v1); + return; + } + sw_vertex_t tv0, tv1; int x0 = (int)v0->position[0]; @@ -6039,7 +5927,7 @@ static void SW_RASTER_LINE_THICK(const sw_vertex_t *v0, const sw_vertex_t *v1) int dx = x1 - x0; int dy = y1 - y0; - SW_RASTER_LINE(v0, v1); + SW_RASTER_LINE_THIN(v0, v1); if ((dx != 0) && (abs(dy/dx) < 1)) { @@ -6050,11 +5938,11 @@ static void SW_RASTER_LINE_THICK(const sw_vertex_t *v0, const sw_vertex_t *v1) tv0 = *v0, tv1 = *v1; tv0.position[1] -= i; tv1.position[1] -= i; - SW_RASTER_LINE(&tv0, &tv1); + SW_RASTER_LINE_THIN(&tv0, &tv1); tv0 = *v0, tv1 = *v1; tv0.position[1] += i; tv1.position[1] += i; - SW_RASTER_LINE(&tv0, &tv1); + SW_RASTER_LINE_THIN(&tv0, &tv1); } } else if (dy != 0) @@ -6066,35 +5954,31 @@ static void SW_RASTER_LINE_THICK(const sw_vertex_t *v0, const sw_vertex_t *v1) tv0 = *v0, tv1 = *v1; tv0.position[0] -= i; tv1.position[0] -= i; - SW_RASTER_LINE(&tv0, &tv1); + SW_RASTER_LINE_THIN(&tv0, &tv1); tv0 = *v0, tv1 = *v1; tv0.position[0] += i; tv1.position[0] += i; - SW_RASTER_LINE(&tv0, &tv1); + SW_RASTER_LINE_THIN(&tv0, &tv1); } } } -#endif // RLSW_TEMPLATE_RASTER_LINE +#endif // SW_RASTER_LINE_STATES //------------------------------------------------------------------------------------------- // Point rasterization functions //------------------------------------------------------------------------------------------- -#ifdef RLSW_TEMPLATE_RASTER_POINT +#ifdef SW_RASTER_POINT_STATES -// Options: -// - RLSW_TEMPLATE_RASTER_POINT -> Contains the suffix name -// - SW_ENABLE_DEPTH_TEST -// - SW_ENABLE_BLEND - -#define SW_RASTER_POINT_PIXEL SW_CONCATX(sw_raster_point_pixel_, RLSW_TEMPLATE_RASTER_POINT) -#define SW_RASTER_POINT SW_CONCATX(sw_raster_point_, RLSW_TEMPLATE_RASTER_POINT) +#define SW_RASTER_POINT_FLAGS SW_FLAGS(SW_RASTER_POINT_STATES) +#define SW_RASTER_POINT_PIXEL SW_CONCATX(sw_raster_point_pixel_, SW_NAME(SW_RASTER_POINT_STATES)) +#define SW_RASTER_POINT SW_CONCATX(sw_raster_point_, SW_NAME(SW_RASTER_POINT_STATES)) static void SW_RASTER_POINT_PIXEL(int x, int y, float z, const float color[4]) { int offset = y*RLSW.colorBuffer->width + x; - #ifdef SW_ENABLE_DEPTH_TEST + #if (SW_RASTER_POINT_FLAGS) & SW_STATE_DEPTH_TEST { uint8_t *dPtr = (uint8_t *)(RLSW.depthBuffer->pixels) + offset*SW_FRAMEBUFFER_DEPTH_SIZE; @@ -6109,7 +5993,7 @@ static void SW_RASTER_POINT_PIXEL(int x, int y, float z, const float color[4]) uint8_t *cPtr = (uint8_t *)(RLSW.colorBuffer->pixels) + offset*SW_FRAMEBUFFER_COLOR_SIZE; - #ifdef SW_ENABLE_BLEND + #if (SW_RASTER_POINT_FLAGS) & SW_STATE_BLEND { float dstColor[4]; SW_FRAMEBUFFER_COLOR_GET(dstColor, cPtr, 0); @@ -6140,5 +6024,5 @@ static void SW_RASTER_POINT(const sw_vertex_t *v) } } -#endif // RLSW_TEMPLATE_RASTER_POINT +#endif // SW_RASTER_POINT_STATES //------------------------------------------------------------------------------------------- From 7d4f5f79e70dacb638d2518518bd312ccc86ce73 Mon Sep 17 00:00:00 2001 From: Jairo Correa Date: Thu, 23 Jul 2026 04:38:45 -0300 Subject: [PATCH 88/94] [build][Zig] Fix web examples building all the time (#6006) --- build.zig | 1 - 1 file changed, 1 deletion(-) diff --git a/build.zig b/build.zig index 8d8b2d353..00caf0e70 100644 --- a/build.zig +++ b/build.zig @@ -719,7 +719,6 @@ fn addExamples( .shell_file_path = b.path("src/shell.html"), .install_dir = install_dir, }); - b.getInstallStep().dependOn(emcc_step); const html_filename = try std.fmt.allocPrint(b.allocator, "{s}.html", .{wasm.name}); const emrun_step = emsdk.emrunStep( From 8eb433518d3397da72db90aff32775c26ac2ee7b Mon Sep 17 00:00:00 2001 From: Jairo Correa Date: Thu, 23 Jul 2026 04:39:38 -0300 Subject: [PATCH 89/94] [build][Zig] Update to raygui 5.0 (#6005) --- build.zig.zon | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index 07a1f7400..a7c2a1292 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -12,8 +12,8 @@ .lazy = true, }, .raygui = .{ - .url = "git+https://github.com/raysan5/raygui#3b2855842ab578a034f827c38cf8f62c042fc983", - .hash = "N-V-__8AAHvybwBw1kyBGn0BW_s1RqIpycNjLf_XbE-fpLUF", + .url = "git+https://github.com/raysan5/raygui#3f81e2bd02bf08dcd9d350e8e8b3cf58044d6877", + .hash = "N-V-__8AAPPCmABYkTrLoRGTR6whFQP1bvg7p5vpLsKIcn4G", .lazy = true, }, .emsdk = .{ From 353268b7cf3b41236e5de7c94c355e0c01549b1f Mon Sep 17 00:00:00 2001 From: Felipe Jorge Date: Thu, 23 Jul 2026 04:41:20 -0300 Subject: [PATCH 90/94] [rmodels] Fix GLTF animation interpolation (#6007) --- src/rmodels.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/rmodels.c b/src/rmodels.c index 119ac315a..698b86d29 100644 --- a/src/rmodels.c +++ b/src/rmodels.c @@ -6614,7 +6614,6 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo cgltf_animation_channel *translate; cgltf_animation_channel *rotate; cgltf_animation_channel *scale; - cgltf_interpolation_type interpolationType; }; struct Channels *boneChannels = (struct Channels *)RL_CALLOC(animations[a].boneCount, sizeof(struct Channels)); @@ -6636,8 +6635,6 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo if (boneIndex == -1) continue; // Animation channel for a node not in the skeleton - boneChannels[boneIndex].interpolationType = animData.channels[j].sampler->interpolation; - if (animData.channels[j].sampler->interpolation != cgltf_interpolation_type_max_enum) { if (channel.target_path == cgltf_animation_path_type_translation) @@ -6689,7 +6686,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo if (boneChannels[k].translate) { - if (!GetPoseAtTimeGLTF(boneChannels[k].interpolationType, boneChannels[k].translate->sampler->input, boneChannels[k].translate->sampler->output, time, &translation)) + if (!GetPoseAtTimeGLTF(boneChannels[k].translate->sampler->interpolation, boneChannels[k].translate->sampler->input, boneChannels[k].translate->sampler->output, time, &translation)) { TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load translate pose data for bone %s", fileName, bones[k].name); } @@ -6697,7 +6694,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo if (boneChannels[k].rotate) { - if (!GetPoseAtTimeGLTF(boneChannels[k].interpolationType, boneChannels[k].rotate->sampler->input, boneChannels[k].rotate->sampler->output, time, &rotation)) + if (!GetPoseAtTimeGLTF(boneChannels[k].rotate->sampler->interpolation, boneChannels[k].rotate->sampler->input, boneChannels[k].rotate->sampler->output, time, &rotation)) { TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load rotate pose data for bone %s", fileName, bones[k].name); } @@ -6705,7 +6702,7 @@ static ModelAnimation *LoadModelAnimationsGLTF(const char *fileName, int *animCo if (boneChannels[k].scale) { - if (!GetPoseAtTimeGLTF(boneChannels[k].interpolationType, boneChannels[k].scale->sampler->input, boneChannels[k].scale->sampler->output, time, &scale)) + if (!GetPoseAtTimeGLTF(boneChannels[k].scale->sampler->interpolation, boneChannels[k].scale->sampler->input, boneChannels[k].scale->sampler->output, time, &scale)) { TRACELOG(LOG_INFO, "MODEL: [%s] Failed to load scale pose data for bone %s", fileName, bones[k].name); } From 127e7441da732b6ede0c656241c40c77ab9079b6 Mon Sep 17 00:00:00 2001 From: Matthew Roush Date: Thu, 23 Jul 2026 03:50:11 -0400 Subject: [PATCH 91/94] [rshapes] Fix `DrawPolyLinesEx()` (#6004) If `innerRadius` is less than 0, it causes the outline to overlap itself and even grow outside of the polygon's bounds when `thick` is greater than `radius`. Clamping `innerRadius` to 0 fixes these problems. --- src/rshapes.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/rshapes.c b/src/rshapes.c index 7292212b1..0f4ae8ead 100644 --- a/src/rshapes.c +++ b/src/rshapes.c @@ -1260,10 +1260,12 @@ void DrawPolyLines(Vector2 center, int sides, float radius, float rotation, Colo void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, float thick, Color color) { + if (thick <= 0.0f) return; + if (sides < 3) sides = 3; float centralAngle = rotation*DEG2RAD; float exteriorAngle = 360.0f/(float)sides*DEG2RAD; - float innerRadius = radius - (thick*cosf(DEG2RAD*exteriorAngle/2.0f)); + float innerRadius = fmaxf(0.0f, radius - (thick*cosf(DEG2RAD*exteriorAngle/2.0f))); #if SUPPORT_QUADS_DRAW_MODE rlSetTexture(GetShapesTexture().id); From f0a8201733136e494abd1e210f2fead5bbd4d023 Mon Sep 17 00:00:00 2001 From: Ray Date: Thu, 23 Jul 2026 12:15:38 +0200 Subject: [PATCH 92/94] Update CHANGELOG for upcoming `raylib 6.2` release --- CHANGELOG | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index eaf467294..578b45ba0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,6 +3,170 @@ changelog Current Release: raylib 6.0 (23 April 2026) +------------------------------------------------------------------------- +Release: raylib 6.2 (xx Aug? 2026) +------------------------------------------------------------------------- +KEY CHANGES: + - REDESIGNED: Image API for more alignment with Texture API + - REDESIGNED: File API for more standard return result values + - ... + +Detailed changes (until 21-Jul-2026): + +[rcore] ADDED: `IsPathDirectory()`, for convenience and more readability at user code by @raysan5 +[rcore] ADDED: `IsPathAbsolute()`, check absolute paths by @raysan5 +[rcore] REVIEWED: `File*()` functions for consistent return result value by @raysan5 -WARNING- +[rcore] REVIEWED: Not updating mouse.previousPosition when `SeMousePosition()` #5962 by @raysan5 -WARNING- +[rcore] REVIEWED: Use `rlgl` provided interface instead of `rlsw` direct access by @raysan5 +[rcore] REVIEWED: Set mouse position to (0,0) when mouse leaves window area #5945 by @raysan5 +[rcore] REVIEWED: Multiple string boundary handling (#5812) by @zhaob1n +[rcore] REVIEWED: Gamepad lower-bound guard to six sibling functions (#5938) by @mahirhir +[rcore] REVIEWED: Fix logging format for automation event capacity warning (#5986) by @GideonSerf +[rcore] REVIEWED: Fix initial macOS window size (#5967) by @loukamb +[rcore] REVIEWED: Fix clipboard image memory leak (#5968) by @LuisR385 +[rcore] REVIEWED: `TakeScreenshot()`, support absolute paths by @raysan5 +[rcore] REVIEWED: `OpenURL()`, added some safety checks to mitigate malicious url inputs - ROS: `CLN-002 by @raysan5 -WARNING- +[rcore] REVIEWED: `LoadAutomationEventList()` - ROS: `CLN-005`, `CLN-006` by @raysan5 +[rcore] REVIEWED: `GetWindowHandle()`, to be consistent between backends, fix #5885 by @raysan5 +[rcore] REVIEWED: `GetTime()`, small addition for RPI Pico 2 by @raysan5 +[rcore] REVIEWED: `GetCurrentMonitor()`, fix for integer overflow in distance calculation (#5842) by @Vasilis-Narain +[rcore] REVIEWED: `FileMove()`, additional security checks by @raysan5 +[rcore] REVIEWED: `FileCopy()`, create directory to copy if it does not exist (#5920) by @InviseDivine +[rcore] REVIEWED: `FileMove()`, fix deleting files if `FileCopy()` fails (#5806) by @Lucrecious -WARNING- +[rcore] REVIEWED: `ComputeSHA1()`, fix undefined behaviour (#5957) by @TheFissk +[rcore] REVIEWED: `GetGamepadAxisCount()`, `GetGamepadName()`, bounds-check gamepad index (#5937) by @szarta +[rcore][GLFW] REVIEWED: `GetClipboardImage()`, fix creating new connection under X11 (#5871) by @steampuker +[rcore][RGFW] REVIEWED: Add fullscreen behaviour on size 0 window creation (#5859) by @keks137 +[rcore][SDL] REVIEWED: Use precise mouse wheel values (#5830) by @Menduist +[rcore][SDL] REVIEWED: Fix SDL3 wrong joystick functions usage (#5948) by @0xFishbyte +[rcore][DRM] REVIEWED: Silence warnings when using GRAPHICS_API_OPENGL_SOFTWARE (#5839) by @NighthowlerStudios +[rcore][DRM] REVIEWED: Segfault on some NVIDIA proprietary drivers (#5960) by @girvel +[rcore][Web] REVIEWED: Fix for stale mouse position (#5981) by @largenumberhere +[rcore][Win32] REVIEWED: Use `CORE.Input.Keyboard.exitKey` when handling window closing (#5911) by @aceinetx +[rcore][Win32] REVIEWED: Security fixes (#5899) by @M374LX +[rcore][Android] REVIEWED: Restore face-button input on Android gamepads (#5824) by @Tubbles +[rlsw] ADDED: Double buffering support and compiler requirements Pico 2 (#5994) by @NighthowlerStudios +[rlsw] ADDED: `GL_SHADING_LANGUAGE_VERSION` for `swGetString()` by @raysan5 +[rlsw] REVIEWED: Variant dispatch refactor and render optimizations (#5996) by @Bigfoot71 +[rlgl] REVIEWED: `rlGetPixelDataSize()`, fix pixel data size regressions (#5984) by @GideonSerf +[rlgl] REVIEWED: `rlPushMatrix()`, fix matrix stack overflow (#5935) by @szarta +[rlgl] REVIEWED: `rlLoadTexture()`, add power-of-two check for GL_REPEAT wrap mode (#5820) by @noinodev +[rlgl] REVIEWED: Shader attribute/uniform default names can not be overriden #5925 by @raysan5 +[rlgl] REVIEWED: Fix DRM/EGL segfault on some NVIDIA proprietary drivers (#5960) by @girvel +[rlsw] REVIEWED: Replace `SW_TEXTURE_REPEAT_POT_FAST` with `SW_SUPPORT_NPOT_TEXTURE` (#5901) by @Bigfoot71 +[rlsw] REVIEWED: Fix triangle and quad spans applying pixels out of bounds (#5849) by @NighthowlerStudios +[rlsw] REVIEWED: Fix swScissor() Y-axis clipping inversion in software renderer (#5976) by @thiagomucci +[rlsw] REVIEWED: Fix persistent alpha blending state (#5964) by @iztanos +[rlsw] REVIEWED: ESP32 optimizations (#5827) by @jensroth-git +[rshapes] RENAMED: `GetSplinePointBezierQuad()` to `GetSplinePointBezierQuadratic()` by @raysan5 -WARNING- +[rshapes] REVIEWED: Reorder drawing functions by number of vertices by @raysan5 +[rshapes] REVIEWED: Comments to be more descriptive by @raysan5 +[rshapes] REVIEWED: `DrawRectangleRoundedLinesEx()`, not scaling with transform when thick=1 (#5980) by @SamaelHeaven +[rshapes] REVIEWED: `DrawRectangleRoundedLines()` (#5992) by @MatthewRoush +[rshapes] REVIEWED: `DrawRectangleRounded()`, automatic segments count (#5875) by @anstropleuton +[rshapes] REVIEWED: `DrawRectangleRounded()`, `DrawRectangleRoundedLinesEx()`, fix auto segment rounded-corner math (#5883) by @ghera +[rshapes] REVIEWED: `CheckCollisionLines()`, add NULL check (#5802) by @bielern +[rtextures] ADDED: `ImageDrawLineStrip()` by @raysan5 +[rtextures] ADDED: `DrawTriangleGradient()` by @raysan5 +[rtextures] ADDED: `DrawCircleLinesEx()`, simpler naming than `DrawRing()` by @raysan5 +[rtextures] ADDED: TODO: `ImageDrawCircleGradient()` by @raysan5 +[rtextures] ADDED: Support for .pep image fileformat, useful for pixel-art by @raysan5 +[rtextures] RENAMED: `ImageDrawTriangleEx()` to `ImageDrawTriangleGradient()` by @raysan5 -WARNING- +[rtextures] REDESIGNED: `ImageDraw()`, align with `DrawTexture()` by @raysan5 -WARNING- +[rtextures] REDESIGNED: `ImageDrawRectangleLines()`, consistency with `DrawRectangleLines()` by @raysan5 -WARNING- +[rtextures] REVIEWED: `LoadImageFromTexture()` for wasm by @raysan5 +[rtextures] REVIEWED: `ImageFromImage()` - ROS: `CLN-007` by @raysan5 +[rtextures] REVIEWED: `ImageFromImage()`, rectangle validation using strict comparisons (#5979) by @CommandPrompt-Wang +[rtextures] REVIEWED: `ImageFromImage()` heap-buffer-overflow on compressed formats (#5991) by @gummyniki +[rtextures] REVIEWED: `ImageToImage()`, reorganize conditionals checks optimization by @raysan5 +[rtextures] REVIEWED: `ImageDrawLine()`, rounding and length fix (#5896) by @Kaggen67 +[rtextures] REVIEWED: `ImageColorContrast()` parameter type, consistent with other `Image*()` functions by @raysan5 -WARNING- +[rtextures] REVIEWED: `GetPixelDataSize()`, avoid allocations >2GB - ROS: `CLN-013` by @raysan5 +[rtextures] REVIEWED: `GetPixelColor()` const by @raysan5 +[rtext] REVIEWED: `LoadFontEx()`, `LoadFontFromMemory()`, additional warnings (#5864) by @CrackedPixel +[rtext] REVIEWED: `TextToSnake()`, not considering spaces properly by @raysan5 +[rtext] REVIEWED: `TextSubtext()`, fix returning empty string when position is 0 (#5975) by @thiagomucci +[rtext] REVIEWED: `TextReplaceBetween()`, fix buffer overflow (#5936) by @szarta +[rtext] REVIEWED: `TextInsertAlloc()`, overflow by correcting loop bounds (#5982) by @GideonSerf +[rtext] REVIEWED: `TextJoin()`, `TextSubtext()`, `TextInsert*()` - ROS: `CLN-018` by @raysan5 +[rmodels] REDESIGNED: `DrawCapsule()`, `DrawCapsuleWires()`, parameter order by @raysan5 -WARNING- +[rmodels] REVIEWED: Fix glTF skinning when joints have non-joint parent nodes (#5876) by @cseelhoff +[rmodels] REVIEWED: Change `boneCount` field type to `unsigned int` (#5955) by @lauchimoon +[rmodels] REVIEWED: `LoadGLTF()`, use inverse bind matrices for bind pose (#5832) by @fyl2xp1 +[rmodels] REVIEWED: `IsModelValid()` #5780 by @raysan5 +[rmodels] REVIEWED: `GenMeshTorus()`, improved comments (#5934) by @EugenioBarbieriViale +[rmodels] REVIEWED: `DrawSphereWires()`, code optimization (#6000) by @oscujic +[rmodels] REVIEWED: `DrawCapsule()`, `DrawCapsuleWires()`, validate minimum rings (#5909) by @LuisR385 +[rmodels] REVIEWED: `UnloadModel()`, fix memory leak (#5907) by @LuisR385 +[raudio] REVIEWED: `UpdateSound()`, missleading parameter name by @raysan5 +[raudio] REVIEWED: `UnloadSoundAlias()`, prevent leak (#5857) by @Peter0x44 +[raudio] REVIEWED: Remove extra `drflac_free()` call (#5916) by @CrackedPixel +[raudio] REVIEWED: Fix memory leak when loading .wav files (#5963) by @LuisR385 +[raudio] REVIEWED: Define missing `UnloadFileData()` on standalone mode (#5787) by @rigidatoms +[raudio] REVIEWED: Update to latest DR libs to fix some warnings in MSVC (#5808) by @JeffM2501 +[raymath] ADDED: Operator overload for (float * Vector) (#5815) by @alphahex99 + +[build] REMOVED: Unmaintained project: 4coder by @raysan5 +[build] REMOVED: Unmaintained project: VS2019-Android by @raysan5 +[build][Make] REVIEWED: Add `ANDROID_ARCH` check (#5888) by @Fipaan +[build][Make] REVIEWED: Re-enable `GLFW_LINUX_ENABLE_WAYLAND` flag by default #5816 by @raysan5 +[build][CMake] ADDED: Support for Win32 platform + examples (#5855) by @CrackedPixel +[build][CMake] REVIEWED: Fix config.h parsing into cmake options (#5844) by @Peter0x44 +[build][CMake] REVIEWED: Add configure-time test for libatomic requirement (#5847) by @Peter0x44 +[build][CMake] REVIEWED: Remove `raudio` and `rmodels` modules if disabled (#5878) by @NighthowlerStudios +[build][CMake] REVIEWED: Remove GLFW_BUILD warnings for platform SDL (#5865) by @jestarray +[build][CMake] REVIEWED: Reduce minimum CMake version from 3.25 to 3.22 (#5890) by @RobLoach +[build][CMake] REVIEWED: Fix static link dependencies (#5990) by @meta-legend +[build][Zig] REVIEWED: Avoid building examples all the time (#5869) by @jn-jairo +[build][Zig] REVIEWED: `build.zig` to support wasm examples (#5811) by @shadeops +[build][CI] REVIEWED: GitHub Actions update to latest actions versions by @raysan5 +[build][CI] REVIEWED: `build_examples_windows.yml`, use latest actions versions by @raysan5 +[build][CI] REVIEWED: `analyze_codeql.yml`, use latest actions versions by @raysan5 +[build][CI] REVIEWED: `setup-emsdk`, use latest actions version by @raysan5 + +[bindings] ADDED: sola-raylib (6.0) (#5790, #5795) by @brettchalupa +[bindings] ADDED: gclang-raylib (6.0) (#5850) by @gnuchanos +[bindings] UPDATED: vala-vapi to raylib 6.0 (#5789) by @edwood-grant +[bindings] UPDATED: raylib_dart to raylib 6.0 (#5917) by @dzylikecode +[bindings] UPDATED: raylib4fb to raylib 6.0 (#5813) by @mudhairless +[bindings] UPDATED: raylib-d to raylib 6.0 (#5799) by @schveiguy +[bindings] UPDATED: raylib-cpp to raylib 6.0 (#5785) by @RobLoach +[bindings] UPDATED: raylib-go to raylib 6.0 (#5866) by @JupiterRider +[bindings] UPDATED: raylib-cpp to raylib 6.0 (#5785) by @RobLoach +[bindings] UPDATED: raylib-zig to raylib 6.0 (#5886) by @coal-rock +[bindings] UPDATED: Deno-Raylib to raylib 6.0 (#5821) by @JJLDonley +[bindings] UPDATED: raylib-cs to raylib 6.0 (#5887) by @rgebee +[bindings] UPDATED: ReiLua to raylib 6.0 (#5959) by @nullstare +[bindings] UPDATED: Raylib-lua to raylib 5.5 (#5884) by @keyle +[bindings] UPDATED: Ray4Laz to raylib 6.0 (#5784) by @GuvaCode +[bindings] UPDATED: raylib-ocaml to raylib 6.0 (#5912) by @tjammer +[bindings] UPDATED: raylib-jai to raylib 6.0 (#5928) by @ahmedqarmout2 +[bindings] UPDATED: raylib-c3 to raylib 6.0 (#5819) by @surrealism21 + +[examples] REVIEWED: `core_smooth_pixelperfect` (#5803) by @rose-mtz +[examples] REVIEWED: `core_directory_files` (#5823) by @MAXDVVV +[examples] REVIEWED: `shapes_ball_physics`, move window for ball shake (#5791) by @Sebbl0508 +[examples] REVIEWED: `textures_image_drawing` by @raysan5 +[examples] REVIEWED: `models_basic_voxel` by @raysan5 +[examples] REVIEWED: `models_animation_blending` by @raysan5 +[examples] REVIEWED: `shaders_*`, `pbr.fs`, using wrong uniform value (#5965) by @raysan5 + +[rlparser] ADDED: S-Expression output type (#5943) by @VisenDev +[rlparser] REVIEWED: Path fixes (#5794) by @gigamonster256 +[rexm] REVIEWED: Simplify code, latest w64devkit supports `make` directly, no need for `mingw32-make` by @raysan5 +[misc] ADDED: SECURITY.md document by @raysan5 +[misc] REVIEWED: Several functions `const` correctness by @raysan5 +[misc] REVIEWED: `strncpy()` replaced by `snprintf()` for safety by @raysan5 +[misc] REVIEWED: Minimize `long long` usage in all raylib by @raysan5 +[misc] REVIEWED: Comments for consistency and spelling by @raysan5 +[misc] REVIEWED: Some Rectangle parameters with more descriptive names by @raysan5 +[misc] REVIEWED: Shift `__cplusplus` check to a higher level for `bool` type define (#5804) by @lamweilun +[external] ADDED: `rprand_get_value_raw()` to `rprand` library by @raysan5 +[external] UPDATED: `raygui` to latest master (raygui 5.0) by @raysan5 +[external] REVIEWED: `jar_mod_load_file()`, check fread return value (#5840) by @fffaraz +[external] REVIEWED: `tiny_obj_loader` Replace `assert()` by runtime checks - ROS: `CLN-012` by @raysan5 + + ------------------------------------------------------------------------- Release: raylib 6.0 (23 April 2026) ------------------------------------------------------------------------- From a408dd332e427b538c7542025bcc8e07d3338f1e Mon Sep 17 00:00:00 2001 From: Ray Date: Fri, 24 Jul 2026 21:17:11 +0200 Subject: [PATCH 93/94] REVIEWED: `IsPathAbsolute()`, remove `isalpha()` dependency --- src/rcore.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/rcore.c b/src/rcore.c index 27b80b3c9..dd60ab731 100644 --- a/src/rcore.c +++ b/src/rcore.c @@ -2859,13 +2859,13 @@ bool IsPathAbsolute(const char *path) if ((path != NULL) && (path[0] != '\0')) { #if defined(_WIN32) - // UNC path (\\server\share) + // Check UNC path (\\server\share) if ((path[0] == '\\') && (path[1] == '\\')) result = true; - // Drive letter (e.g. C:\ or D:/) - else if (isalpha((unsigned char)path[0]) && (path[1] == ':') && - ((path[2] == '\\') || (path[2] == '/'))) result = true; + // Check path starts with a drive letter (e.g. C:\ or D:/) + else if ((((path[0] >= 'A') && (path[0] <= 'Z')) || ((path[0] >= 'a') && (path[0] <= 'z'))) && + (path[1] != '\0') && (path[1] == ':') && (path[2] != '\0') && ((path[2] == '\\') || (path[2] == '/'))) result = true; #else - // POSIX: must start with / + // Check POSIX path, must start with / if (path[0] == '/') result = true; #endif } From c15f3214d5d934f87f9aabe603db8666d9532b78 Mon Sep 17 00:00:00 2001 From: Matthew Roush Date: Fri, 24 Jul 2026 15:38:50 -0400 Subject: [PATCH 94/94] [rshapes] Correct `DrawPolyLinesEx()` line thickness. (#6014) Follow up to #6004. The previous formula would produce inconsistent results for different polygons with the same `thick` parameter. --- src/rshapes.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/rshapes.c b/src/rshapes.c index 0f4ae8ead..76fb0c3c2 100644 --- a/src/rshapes.c +++ b/src/rshapes.c @@ -1265,7 +1265,8 @@ void DrawPolyLinesEx(Vector2 center, int sides, float radius, float rotation, fl if (sides < 3) sides = 3; float centralAngle = rotation*DEG2RAD; float exteriorAngle = 360.0f/(float)sides*DEG2RAD; - float innerRadius = fmaxf(0.0f, radius - (thick*cosf(DEG2RAD*exteriorAngle/2.0f))); + float apothem = radius*cosf(DEG2RAD*180.0f/(float)sides); + float innerRadius = fmaxf(0.0f, radius - thick*(radius/apothem)); #if SUPPORT_QUADS_DRAW_MODE rlSetTexture(GetShapesTexture().id);